Ibatis的类型处理器TypeHandler解析
Ibatis允许用户像在hibernate中一样定义自己的类型,但是,用户自定义类型需要与数据库中的字段类型进行对应。它的处理方法是允许我们扩展TypeHandler。Ibatis框架在处理该数据类型时就会自动调用TypeHandler进行类型转换,非常方便,ibatis中所有的类型都有它自己的TypeHandler,只是一些常用的数据类类型它已经给我们实现了而已。
在配置文件中,我们有两个地方可以配置这种处理器。
第一个地方是sqlMap文件中标签ResultMap或者ParameterMap中的TypeHandler属性,这里配置的handler是局部属性,只会在该ResultMap中才会进行转换。
<resultMap id="UserOrder" class="UserOrderDO" groupBy="id">
......
<result property="tripType" column="trip_Type"
typeHandler="com.taobao.et.biz.dal.common.EnumTypeHandlerCallBack"/>
......
</resultMap>
第二个地方是sqlMapConfig文件中的标签typeHandlers中配置typeHandle子标签,这里配置的标签是全局属性,任何只要匹配该子标签的地方都会自动使用该Handler.
<typeHandlers>
<typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
</typeHandlers>
例如这里的全局配置,如果此时某个数据库字段的jdbcType是CLOB类型,并且映射的JavaType类型是字符串类型,那么就会自动调用这里的callback来实行类型转换。
那么Ibatis是如何确定使用哪一个TypeHandler的呢?!
它会在自己的局部区域寻找是否在配置文件中配置了Handler,找到了就使用这个handler,如果没有找到,就会查找是否有全局handler,也就是第二种方式配置的handler,这里要注意,可能我们也没有在全局配置文件中配置handler,此时,Ibatis就会根据实际类型配置默认的handler。
我们来看一些关键代码,按照查找步骤,这里我去掉了异常,只看关键的部分。
第一步:从局部Reultmap中取出配置属性。
String propertyName = childAttributes.getProperty("property");
String nullValue = childAttributes.getProperty("nullValue");
String jdbcType = childAttributes.getProperty("jdbcType");
String javaType = childAttributes.getProperty("javaType");
String columnName = childAttributes.getProperty("column");
String columnIndex = childAttributes.getProperty("columnIndex");
String statementName = childAttributes.getProperty("select");
String resultMapName = childAttributes.getProperty("resultMap");
String callback = childAttributes.getProperty("typeHandler");
callback = vars.typeHandlerFactory.resolveAlias(callback);
javaType = vars.typeHandlerFactory.resolveAlias(javaType);
TypeHandler handler = null;
if (callback != null) { // 注意这里,如果配置了就使用这个配置的handler
Object impl = Resources.classForName(callback).newInstance();
if (impl instanceof TypeHandlerCallback) {
handler = new CustomTypeHandler((TypeHandlerCallback) impl);
} else if (impl instanceof TypeHandler) {
handler = (TypeHandler) impl;
} else {
throw new NestedRuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
}
} else {//如果没有配置,就到这里来找
handler = resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(), vars.currentResultMap.getResultClass(), propertyName, javaType, jdbcType, true);
}
第二步,如果局部配置中没有找到,就到下面去找。
public TypeHandler resolveTypeHandler(TypeHandlerFactory typeHandlerFactory, Class clazz, String propertyName, String javaType, String jdbcType, boolean useSetterToResolve) {
TypeHandler handler = null;
if (clazz == null) {
// Unknown
handler = typeHandlerFactory.getUnkownTypeHandler();
} else if (DomTypeMarker.class.isAssignableFrom(clazz)) {
// DOM
handler = typeHandlerFactory.getTypeHandler(String.class, jdbcType);
} else if (java.util.Map.class.isAssignableFrom(clazz)) {
// Map
if (javaType == null) {
handler = typeHandlerFactory.getUnkownTypeHandler(); //BUG 1012591 - typeHandlerFactory.getTypeHandler(java.lang.Object.class, jdbcType);
} else {
try {
Class javaClass = Resources.classForName(javaType);
handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
} catch (Exception e) {
throw new NestedRuntimeException("Error. Could not set TypeHandler. Cause: " + e, e);
}
}
} else if (typeHandlerFactory.getTypeHandler(clazz, jdbcType) != null) {
// Primitive
handler = typeHandlerFactory.getTypeHandler(clazz, jdbcType);
} else {
// JavaBean
if (javaType == null) {
if (useSetterToResolve) {
Class type = PROBE.getPropertyTypeForSetter(clazz, propertyName);
handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
} else {
Class type = PROBE.getPropertyTypeForGetter(clazz, propertyName);
handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
}
} else {
try {
Class javaClass = Resources.classForName(javaType);
handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
} catch (Exception e) {
throw new NestedRuntimeException("Error. Could not set TypeHandler. Cause: " + e, e);
}
}
}
return handler;
}
- 相信大家已经很明白了,其实要找一个Handler,主要就是需要javaType和jdbcType,而这两个参数要么通过反射得到,要么通过配置文件中得到。因此,为了明确我们一般都在配置文件中进行申明。
- 最后来看一点 typeHandlerFactory.getTypeHandler(clazz, jdbcType)是怎么实现的。
public TypeHandler getTypeHandler(Class type, String jdbcType) {
Map jdbcHandlerMap = (Map) typeHandlerMap.get(type);//首先根据JAVA类型
TypeHandler handler = null;
if (jdbcHandlerMap != null) {
handler = (TypeHandler) jdbcHandlerMap.get(jdbcType);//每个JDBC类型
if (handler == null) {
handler = (TypeHandler) jdbcHandlerMap.get(null);
}
}
return handler;
}
其实一个Handler=javaType+jdbcType 。
Ibatis的类型处理器TypeHandler解析的更多相关文章
- MyBatis源码解析(十)——Type类型模块之类型处理器TypeHandler
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6715063.html 1.回顾 之前的两篇分别解析了类型别名注册器和类型处理器注册器,此二 ...
- MyBatis(九):MyBatis类型处理器(TypeHandler)详解
TypeHandler简介 TypeHandler,顾名思义类型转换器,就是将数据库中的类型与Java中的类型进行相互转换的处理器. MyBatis 在设置预处理语句(PreparedStatemen ...
- 浩哥解析MyBatis源码(十)——Type类型模块之类型处理器
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6715063.html 1.回顾 之前的两篇分别解析了类型别名注册器和类型处理器注册器,此二 ...
- 浩哥解析MyBatis源码(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6709157.html 1.回顾 上一篇研究的是类型别名注册器TypeAliasRegist ...
- MyBatis源码解析(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6709157.html 1.回顾 上一篇研究的是类型别名注册器TypeAliasRegist ...
- MyBatis 源码分析——类型处理器
官网上面讲到:无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型.那 ...
- mybatis 3的TypeHandler解析(null值的处理)
最近,在测试迁移公司的交易客户端连接到自主研发的中间件时,调用DAO层时,发现有些参数并没有传递,而在mapper里面是通过parameterMap传递的,因为有些参数为null,这就导致了参数传递到 ...
- mybatis学习系列五--插件及类型处理器
2 插件编写(80-81) 单个插件编写 2.1实现interceptor接口(ibatis) invocation.proceed()方法执行必须要有,否则不会无法实现拦截作用 2.2 使用@int ...
- MyBatis从入门到精通(十四):在MyBatis中使用类型处理器
最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解在MyBatis中如何 ...
随机推荐
- Linux root 密码重置与用户管理
---forget root password restart your linux system press 'e' when start. press 'e' again then choose ...
- Selenium2怎么调用selenium1中方法
虽然selenium1.0已经成为过去时,现在都用selenium2.0,但是如果想要在代码中调用selenium1.0的api怎么办,看下面 WebDriver driver = new Chrom ...
- java GUI,贷款服务器
本习题来自<java语言程序设计--进阶篇>第30章,网络编程的习题. 题目描述:为一个客户端编写一个服务器.客户端向服务器发送贷款信息(年利率.贷款年限和贷款总额).服务器计算月偿还额和 ...
- 移动web页面使用的字体的思考
前言 记得做PC端页面的时候,字体一般设置为微软雅黑,现在做起移动端页面来了,设计师们一般都还把字体设置为微软雅黑字体,但是做出来后,测试的时候发现页面中的字体不是微软雅黑,怎么办? 后来了解到的手机 ...
- javascript中的this应用
1. this作为全局变量2. 作为对象方法的调用3. 作为构造函数调用4. apply调用 this是Javascript语言的一个关键字.它代表函数运行时,自动生成的一个内部对象,只能在函数内部使 ...
- 富有表现力的javascript
1.javascript的灵活性,你可以把它写的很简单,也可以写的很复杂,简直就是随心所欲: 2.javascript是弱类型语言,定义变量的时候不用声明变量类型,不声明类型,并不是说,javascr ...
- C# WinForm 中Console 重定向输出到ListBox控件中显示
{ VoidAction action = { lstBox.Items. ...
- NSURLSession学习笔记
NSURLSession学习笔记(一)简介 一.URL Session的基本概念 1.三种工作模式: 默认会话模式(default):工作模式类似于原来的NSURLConnection,使用的是基于磁 ...
- wid是一个字符串 必须转化成整型
wid是一个字符串 必须转化成整型
- Discuz! X的CSS加载机制
首先,每个页面都会加载以下两个css,data/cache/style_1_common.css和data/cache/style_1_forum_index.css.先讲讲这两个文件名的命名规则:第 ...