Mybatis中类型映射处理器详解
上一篇梳理了Configuration初始化分析,今天继续typeHandlers部分。
数据库厂商标识
接上一篇文章分析,下一个解析的是databaseIdProvider节点,这个节点好理解,从字面理解就是数据库提供商的id,也就是mybatis需要访问的数据库是那种数据库。
我们都知道mybatis只是一个ORM框架,并不是针对具体的数据库,需要兼容多种数据库,所以mybatis可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的databaseId 属性。
解析在配置文件中配置的源码如下图:
可以看到最终是返回一个字符串给到configuration的databaseId属性,同时我们也可以自己实现一个DatabaseIdProvider,不过要先在别名配置里面配置好。
类型处理器
因为无论是 MyBatis 预处理语句(PreparedStatement)中设置参数时,还是从结果集中取出一个值时, 都需要jdbc的数据类型和Java数据类型进行相互转换,而类型处理器就是提供这个功能的,mybatis解析的源码如下图:
typeHandlerElement(root.evalNode("typeHandlers"));是解析类型映射器代码,从typeHandlerElement方法可以知道类型解析器支持两个方法,与别名一样支持包扫描和具体类型。包扫描和别名差不多流程,都是找到对应包下面所有类,然后解析放到TypeHandlerRegistry类中。
从上图源码中可以看出要实现Java类型到jdbc类型的相互映射需要三个类:Java类型,JDBC类型,Handler。获取到这个对象后调用TypeHandlerRegistry的register方法注册到TypeHandlerRegistry中去,那么这几个对象的关系该是如何映射的呢?
TypeHandlerRegistry对象保存有Java类型和JDBC类型的对应关系,从上图中TypeHandlerRegistry源码可以看到几个重要属性就能明白mybatis是如何实现类型间的映射了。关键属性解释如下:
Map<JdbcType,TypeHandler<?>> jdbcTypeHandlerMap:记录JdbcType和TypeHandler之间的对应关系,其中JdbcType是一个枚举类型,它定义对应的JDBC类型,该集合主要用于从结果集读取数据时,将数据从Jdbc类型转换成Java类型;
Map<Type,Map<JdbcType,TypeHandler<?>>> typeHandlerMap :记录了Java类型向指定的JdbcType转换时,需要使用的TypeHandler对象,因为一个Java类型可能对应多个数据库类型,比如Java类型中的String可能转换成数据库的char、varchar等多种类型,所以存在一对多的关系,所以值要用Map来存储;
TypeHandler<Object>unknownTypeHandler:一些未知类型对象的TypeHandler;
Map<Class<?>, TypeHandler<?>> allTypeHandlersMap:记录了全部TypeHandler的类型以及该类型相应的TypeHandler对象;
最关键是前面两个属性,jdbcTypeHandlerMap用于查询结果转Java时使用,typeHandlerMap 用于在Java类型转jdbc类型时使用。
在上图右侧的TypeHandlerRegistry源码中可以看到两个构造方法,会先把Configuration中一些类型映射生成unknownTypeHandler属性,然后对常见的类型映射进行了初始化。
类型处理器自定义
从上面的源码中可以得出要自定义一个类型处理器只需要实现TypeHandler接口就行,并实现它的4个方法,这里实现了一个处理List集合的处理器,源码如下图:
这四个方法还是挺简单的,第一个方法是在保存操作是把List对象转换成字符串设置到保存sql语句中,后面三个方法是在查出数据后再转换成List。
创建好了就是使用了,使用的关键代码如下图:
首先在配置文件中配置创建的类型,然后在插入的sql那里指定字段的处理器,然后就可以插入了,可以看到保存到数据库的结果和查询出来的结果,基本满足要求了。
总结
数据库id我们一般很少自己配置,除非有特殊需求,这里主要讲了类型处理器,有时候还是可以用上的。
这里只是实现了集合映射到数据的处理器,有时候我们还可能使用到枚举到数据库的映射,有兴趣的同学可以去了解下,也是比较简单的。
Configuration的初始化还是最后一个mapper的加载了,本来想在这篇完结的,发现mapper的内容太多,下一篇来详细梳理下。
Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!