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中如何 ...
随机推荐
- Combine small files to Sequence file
Combine small files to sequence file or avro files are a good method to feed hadoop. Small files in ...
- MIT jos 6.828 Fall 2014 训练记录(lab 2)
注: 源代码参见我的github:https://github.com/YaoZengzeng/jos Part1 : Physical Page Management mem_init函数: /*该 ...
- 循环队列+堆优化dijkstra最短路 BZOJ 4152: [AMPPZ2014]The Captain
循环队列基础知识 1.循环队列需要几个参数来确定 循环队列需要2个参数,front和rear 2.循环队列各个参数的含义 (1)队列初始化时,front和rear值都为零: (2)当队列不为空时,fr ...
- Debian安装中文输入法
简单暴力: apt-get install ibus-pinyin 你也可以通过GUI下面到Synaptic Package Manager里面选中ibus-pinyin进行安装 安装完成后重启计算机 ...
- 对Spring的IoC和DI最生动的解释
首先想说说IoC(Inversion of Control,控制倒转).这是spring的核心,贯穿始终.所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系 ...
- [推荐] BC/Beyond Compare(差异比较软件)
Beyond Compare 前一段时间,介绍过用Total Commander来完成文件夹同步的时候,一位朋友留言推荐了Beyond Compare--一个强大的超越了文件差异比较的工具.Beyon ...
- QTP基础学习(一)安装目录介绍
上一篇介绍了QTP 10 安装,安装完成后就可以看到文件的目录了,这里主要介绍以下几个目录及作用. 简单介绍部分目录 1.addins:插件包 2.bin目录:可执行程序,这里存储了很多配置文件.运行 ...
- js中接口的声明与实现
实现接口,必须实现接口里的所有方法. function Interface(name,fns){//声明一个接口类 this.name = name; th ...
- javascript中的数组操作
1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限, ...
- [解决方案]在Sql Server 2008/2005 数据库还原出现 3154错误
在Sql Server 2008/2005 数据库还原出现 3154错误 解决方法1:不要在数据库名字上点右键选择还原,而要是在根目录“数据库”三个字上点右键选择还原,然后再选择数据库,问题便可以解决 ...