[Mybatis] TypeHandler的简单应用及源码分析

来源:互联网 发布:mysql数据库同步 日志 编辑:程序博客网 时间:2024/06/05 03:55

TypeHandlers

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

下面是常见的一些对应类型:
对应类型示例

以BigDecimalTypeHandler看一下,它主要完成了哪些工作。
BigDecimalTypeHandler

这个类的第一个方法是对预处理语句(PreparedStatement)设置参数,之后的三个函数都是从ResultSet或者用于执行存储过程的CallableStatement语句中获取BigDecimal类型的数值,用于向BigDecimal类型的Java字段赋值。
BigDecimalTypeHandler继承的BaseTypeHandler是个泛型类,其他的TypeHandler也是通过继承这个抽象类,实现其中的抽象方法,实现类型转换的工作。
输入图片说明

这个抽象类实现了TypeHandler接口,这个接口主要定义了类型转换的几种操作。
输入图片说明

至于这个抽象类继承的TypeReference,主要是提供了获取这个T具体是哪个类型。在判断使用使用哪个TypeHandler时有用,后文会看到。
输入图片说明


如何使用

大致介绍了TypeHandler的作用,及其相关类,我们来看看如何使用它。
今天遇到的主要是从SqlServer中取数据,遇到很多列都是Numeric(10,2)类型,指的是字段是数字型,长度为10,小数为两位。Mybatis默认的BigDecimalTypeHandler取到后,都默认变成4位小数,不够的补了0。而上层的要求是,拿到的和数字相关的数据都要2位小数。

有两种做法,一种是在所有给上层赋值的时候,都人工对BigDeciam的数据做如下操作。

setScale(2, BigDecimal.ROUND_HALF_UP)

因为这是一个全局性的要求,所有相关的地方,都需要有这个代码,虽然可以写一个工具类,各个地方调用,但就对原本间接的代码造成了侵入。既然这样,为什么不试试TypeHandler。

我的做法是继承BigDecimalTypeHandler,覆盖原来的取值方法,对取到的数值做范围限定。

加上@MappedJdbcTypes注解是为了表明这个类是用于映射JdbcType的NUMERIC类型,这会覆盖默认的用于转换Java BegDecimal和Jdbc NUMERIC的BigDecimal,在后面源码中可略窥一二。

开发完这个转换类后,你需要在Mybatis的配置文件中声明这个TypeHandler,这样Mybatis才知道你自己声明了一个TypeHandler。

<typeHandlers>    <typeHandler handler="com.codelab.learn.SubBigDecimalTypeHandler"/></typeHandlers>

这样TypeHandler就起作用了。下面是前后效果。
输入图片说明
输入图片说明


源码层面

首先Mybatis有一个默认的TypeHandler实现,这些TypeHandler是如何被Mybatis识别的呢。
答案是TypeHandlerRegistry。在Mybatis初始化配置的时候,TypeHandlerRegistry会把JdbcType和Java类型对应的映射关系注册进该类内部的Map中。
输入图片说明
输入图片说明
JDBC_TYPE_HANDLER_MAP中记录的是JdbcType和TypeHandler对应的关系。
12
TYPE_HANDLER_MAP中记录的是Java类型和对应的所有JdbcType以及其对应TypeHandler的映射关系关系。
13
UNKNOWN_TYPE_HANDLER是在执行BaseTypeHandler的抽象方法时,去先解析出来该用什么TypeHandler,目前还没用到,先不研究。
ALL_TYPE_HANDLERS_MAP中记录的是所有TypeHandler的Class和其实例之间的映射关系。

我们以系统默认注册的三个作为例子,看看整个执行的流程

1 register(String.class, new StringTypeHandler());2 register(String.class, JdbcType.NCHAR, new NStringTypeHandler());3 register(JdbcType.NCHAR, new NStringTypeHandler());

第一个是告诉 String类型的转换,要用StringTypeHandler。
直接进的这个函数,因为我们的TypeHandler上并没有打注解,因此直接进入箭头标记的逻辑。
输入图片说明

然后继续注册,只不过jdbcType是null。
输入图片说明

后续的代码比较简单,会先从Type_HANLER_MAP中看是否有已经存在的 Map

总结

本文主要介绍了
1. 什么是TypeHandler。
2. 如何使用TypeHandler。
3. 从系统默认的以及自定义的TypeHandler的注册和获取的角度,从源码层面分析了整个过程。


希望得到您的点赞,打赏支持,谢谢。
输入图片说明

原创粉丝点击