mybatis typeHandler类型转换器
typeHandler类型转换器
在JDBC中,需要在PreparedStatement对象中设置那些已经预编译过的SQL语句的参数。执行SQL后,会通过ResultSet对象获取得到数据库的数据,而这些MyBatis是根据数据的类型通过typeHandler来实现的。在typeHandler中,分为jdbcType和javaType,其中jdbcType用于定义数据库类型,而javaType用于定义Java类型,那么typeHandler的作用就是承担jdbcType和javaType之间的相互转换,如图4-1所示。在很多情况下我们并不需要去配置typeHandler、jdbcType、javaType,因为MyBatis会探测应该使用什么类型的typeHandler进行处理,但是有些场景无法探测到。对于那些需要使用自定义枚举的场景,或者数据库使用特殊数据类型的场景,可以使用自定义的typeHandler去处理类型之间的转换问题。
和别名一样,在MyBatis中存在系统定义typeHandler和自定义typeHandler。MyBatis会根据javaType和数据库的jdbcType来决定采用哪个typeHandler处理这些转换规则。系统提供的typeHandler能覆盖大部分场景的要求,但是有些情况下是不够的,比如我们有特殊的转换规则,枚举类就是这样。
系统定义的typeHandler
MyBatis内部定义了许多有用的typeHandler,如表所示。
这些就是MyBatis系统已经创建好的typeHandler。在大部分的情况下无须显式地声明jdbcType和javaType,或者用typeHandler去指定对应的typeHandler来实现数据类型转换,因为MyBatis系统会自己探测。有时候需要修改一些转换规则,比如枚举类往往需要自己去编写规则。
在MyBatis中typeHandler都要实现接口org.apache.ibatis.type.TypeHandler,首先让我们先看看这个接口的定义,如代码清单4-9所示。
代码清单4-9:TypeHandler.java
public interface TypeHandler<T> {
//T是泛型,专指javaType,比如我们需要String的时候,那么实现类可以写为implements TypeHandler<String>。
//setParameter方法,是使用typeHandler通过PreparedStatement对象进行设置SQL参数的时候使用的具体方法,其中i是参数在SQL的下标,parameter是参数,jdbcType是数据库类型。
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; //其中有3个getResult的方法,它的作用是从JDBC结果集中获取数据进行转换,要么使用列名(columnName)要么使用下标(columnIndex)获取数据库的数据,其中最后一个getResult方法是存储过程专用的。
T getResult(ResultSet rs, String columnName) throws SQLException; T getResult(ResultSet rs, int columnIndex) throws SQLException; T getResult(CallableStatement var1, int columnIndex) throws SQLException;
}
在编写typeHandler前,先来研究一下MyBatis系统的typeHandler是如何实现的,所以有必要先研究一下MyBatis系统的typeHandler。如果读者打开源码,就可以发现它们都继承了org.apache.ibatis.type.BaseTypeHandler,如代码清单4-10所示。
代码清单4-10:BaseTypeHandler.java
/**
* BaseTypeHandler是个抽象类,需要子类去实现其定义的4个抽象方法,而它本身实现了typeHandler接口的4个方法。
* @param <T>
*/
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
protected Configuration configuration; public BaseTypeHandler() {
} public void setConfiguration(Configuration c) {
this.configuration = c;
} //setParameter方法,当参数parameter和jdbcType同时为空时,MyBatis将抛出异常。如果能明确jdbcType,则会进行空设置;如果参数不为空,那么它将采用setNonNullPa-rameter方法设置参数。
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
} try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException var7) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + var7, var7);
}
} else {
try {
this.setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception var6) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: " + var6, var6);
}
} } //getResult方法,非空结果集是通过getNullableResult方法获取的。如果判断为空,则返回null。
public T getResult(ResultSet rs, String columnName) throws SQLException {
Object result;
try {
result = this.getNullableResult(rs, columnName);
} catch (Exception var5) {
throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + var5, var5);
} return rs.wasNull() ? null : result;
} public T getResult(ResultSet rs, int columnIndex) throws SQLException {
Object result;
try {
result = this.getNullableResult(rs, columnIndex);
} catch (Exception var5) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set. Cause: " + var5, var5);
} return rs.wasNull() ? null : result;
} public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
Object result;
try {
result = this.getNullableResult(cs, columnIndex);
} catch (Exception var5) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement. Cause: " + var5, var5);
} return cs.wasNull() ? null : result;
} public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException; //getNullableResult方法用于存储过程。
public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException; public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException; public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}
MyBatis使用最多的typeHanlder之一——StringTypeHandler。它用于字符串转换,其源码如代码清单4-11所示。
代码清单4-11:StringTypeHanlder
public class StringTypeHandler extends BaseTypeHandler<String> {
public StringTypeHandler() {
} public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
} public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
} public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
} public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
显然它实现了BaseTypeHandler的4个抽象方法,代码也非常简单。
在这里,MyBatis把javaType和jdbcType相互转换,那么它们是如何注册的呢?在MyBatis中采用org.apache.ibatis.type.TypeHandlerRegistry类对象的register方法进行注册,如代码清单4-12所示。
代码清单4-12:系统注册typeHanlder
public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
//....
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
//....
}
这样就实现了用代码的形式注册typeHandler。注意,自定义的typeHandler一般不会使用代码注册,而是通过配置或扫描
mybatis typeHandler类型转换器的更多相关文章
- mybatis 自定义类型转换器 (后台日期类型插入数据库)
后台日期类型插入数据库 有以下几种发法: 1 调用数据库 日期字符串转日期函数 str_to_date("日期","yyyy-MM-dd HH:mm:ss") ...
- mybatis入门系列三之类型转换器
mybatis入门系列三之类型转换器 类型转换器介绍 mybatis作为一个ORM框架,要求java中的对象与数据库中的表记录应该对应 因此java类名-数据库表名,java类属性名-数据库表字段名, ...
- Mybatis特殊值Enum类型转换器-ValuedEnumTypeHandler
引言 typeHandlers 阅读官方文档 typeHandlers 一节 {:target="_blank"} MyBatis 在预处理语句(PreparedStatement ...
- [原创]Mybatis特殊值Enum类型转换器-ValuedEnumTypeHandler
引言 typeHandlers 阅读官方文档 typeHandlers 一节{:target="_blank"} MyBatis 在预处理语句(PreparedStatement) ...
- (三)Mybatis类型转换器,接口传参类型,一对一,一对多查询resultMap配置
Mybatis类型转换器 首先明白什么时候用到它,当数据库的字段类型和java字段类型无法默认匹配时候进行转换,比如现在数据库类型是INTEGER,而java当中类型是Boolean,true表示1, ...
- Mybatis入门——基础方式的增删该查、mapper动态代理方式的CRUD、类型转换器
一.基础方式的增删该查: 1.mybatis约定:输入参数parameterType和输出参数resulrType在形式上只能有一个. 2.如果输入/输出参数:是简单类型(8个基本类型加String) ...
- mybatis类型转换器 - 自定义全局转换enum
在数据模型.接口参数等场景部分属性参数为一些常量值,比如性别:男.女.若是定义成int或String类型,于是类型本身的范围太宽,要求使用者需要了解底层的业务方可知如何传值,那整体来看增加沟通成本,对 ...
- mybatis typehandler
建立TypeHandler 我们知道java有java的数据类型,数据库有数据库的数据类型,那么我们在往数据库中插入数据的时候是如何把java类型当做数据库类型插入数据库,在从数据库读取数据的时候又是 ...
- MyBatis 示例-类型处理器
MyBatis 提供了很多默认类型处理器,参考官网地址:链接,除了官网提供的类型处理器,我们也可以自定义类型处理器. 具体做法为:实现 org.apache.ibatis.type.TypeHandl ...
随机推荐
- easyui-datagrid统计
<script> //打印指定的table function dayin() { var tableToPrint = document.getElementById("dg&q ...
- 从零开始开发一个Spring Boot Starter
一.Spring Boot Starter简介 Starter是Spring Boot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境( 条件 ...
- Oracle 11g 新特性 -- 自适应游标共享(Adaptive Cursor Sharing: ACS) 说明(转载)
一.自适应游标共享(Adaptive Cursor Sharing) 说明 1.1 ACS概述绑定变量使Oracle DB 可以为多条SQL 语句共享单个游标,以减少分析SQL 语句所使用的共享内存量 ...
- mysql sum的多条件求和
1.无条件求和 sum(字段名): 2.多条件求和 sum(IF(c1>0, c1, 0)); (IF(o.is_cod=0,o.order_amount-IF(b.back_status> ...
- 洛谷 P1613 跑路 题解
P1613 跑路 题目描述 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是为了保住自己的工资,小A买了一个十分牛B的 ...
- 洛谷 P1056 排座椅 题解
P1056 排座椅 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的 \(D\ ...
- [php][thinkphp] 记一次Composer Linux版安装以及用它进行thinkphp项目初始化
Composer安装thinkphp,thinkphp5.1开始官网不在提供下载包,只能通过git clone 和Composer包管理器进行下载. php中开启exec,system等函数调用系统命 ...
- 常用命令备忘 xargs
xargs 作为使用率很高的命令,但是长久不用就会模糊了记忆,所以要记录下来. 获取所有的cobbler相关的布尔值然后全部设置为真 getsebool -a|grep cobbler|awk '{p ...
- 坑:jmeter代理服务器录制脚本出现target controller is configured to "use recording Controller" but no such controller exists...
配置好代理服务器后,运行代理服务器 run 报错: target controller is configured to "use recording Controller" bu ...
- 第12组 Alpha冲刺(2/6)
Header 队名:To Be Done 组长博客 作业博客 团队项目进行情况 燃尽图(组内共享) 展示Git当日代码/文档签入记录(组内共享) 注: 由于GitHub的免费范围内对多人开发存在较多限 ...