mybatis之类型处理器

本篇主要介绍一下 mybatis 的类型处理器,基于3.4.6版本。

知识点

  • 什么是类型处理器
  • 类型处理器的作用
  • 如何自定义类型处理器
  • 实现原理

什么是类型处理器

我们平时在使用 mybatis 的时候比较简单,只要写一个 sql 语句,然后定义好对应的接口就可以使用了,这里就涉及到一个问题:我们调用接口的时候传入的明明是 java 的数据类型,为什么能够正常存到数据库里呢,我们从数据库里取出来的明明是数据库中的类型,为什么能够直接在代码里拿到 java 类型呢?类型处理器就是来解决这个问题的,用 mybatis 的术语,就是 TypeHandler。

类型处理器的作用

其实上面也说到了,类型处理器的作用非常简单,总结起来就2种

  • 将我们传入接口的参数转换为对应的数据库类型
  • 将数据库种查询回来的字段类型转换为对应的java类型

如何自定义类型处理器

我们知道 mybatis 内置了很多类型的处理器,这也是我们什么都不做,直接能够完成类型转换的原因,看下目前有哪些类型处理器
mybatis之类型处理器_第1张图片
可以看到,type目录下几乎全是,有兴趣的可以自己去看下,这里不多做介绍。如果遇到了内置处理器无法处理的新类型,或者我们想要在内置的类型处理器上加一些自己的逻辑,怎么办呢?这时就需要自定义类型处理器了。这个比较简单,其实官方文档里也介绍过了,这里再详细介绍一下
1) 继承 BaseTypeHandler ,我这里处理的是String 类型

public class MyTypeHandler extends BaseTypeHandler {

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
        preparedStatement.setString(i, s);
    }

    @Override
    public String getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return null;
    }

    @Override
    public String getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return null;
    }

    @Override
    public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }

}

2)最简单的情况下上面定义已经可以了,我们还可以自己指定处理器处理的数据库字段类型,通过@MappedJdbcTypes注解来指定,比如我这里要处理的是表中的 varchar 类型数据,如果不指定则默认取 key 为 null 的对应jdbc类型处理器

@MappedJdbcTypes(value = JdbcType.VARCHAR)

3) 另外还可以通过@MappedTypes注解来指定处理对应的 java 类型,如果没指定,则默认取 BaseTypeHandler 中对应的泛型类的实际类型

@MappedTypes(value = String.class)

4) 最后需要在配置中指定类型处理器的路径

mybatis.type-handlers-package=com.example.mybatisanalyze.typehandler

实现原理

注册流程

自定义一个类型处理器如此简单,它的实现原理也不难,我们来看下是如何实现的。这里先看一个非常重要的类TypeHandlerRegistry,该类就是类型处理器管理类,所有的类型处理器都在这里面维护着
mybatis之类型处理器_第2张图片
可以看到在构造函数里就会注册内置的类型处理器。在我们配置了对应的类型处理器所在包路径之后,mybatis-spring 或者 mybatis就会调用对应的注册接口进行注册
mybatis之类型处理器_第3张图片
这里面的逻辑比较简单,就不细说,知道一点就可以:里面维护的 map 结构是 >,也就是先根据 java 类型取到对应的集合,再通过表字段类型取到对应的处理器。

处理流程

对于处理流程,要调试的话,关键看一个类:BaseTypeHandler。这里用到了模板模式,所有的处理器都要先经过基类的模板处理,再调子类的定制化逻辑。它继承的是TypeHandler
mybatis之类型处理器_第4张图片
从对应的接口名称中我们也能看出来,setParameter 是用来将 java 类型转换为表字段类型的,其他的是用来讲表字段类型转换为 java 类型的。我们平时在执行逻辑的时候用的是DefaultSqlSession,以selectOne函数来举例看下是在哪里做类型转换处理的。从org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)一直跟进去
mybatis之类型处理器_第5张图片
这里默认用的缓存执行器,也就是CachingExecutor。继续跟进去
mybatis之类型处理器_第6张图片
缓存不存在的话,会使用 BaseExecutor 来执行查询,中间的链路不多介绍了,直接看org.apache.ibatis.executor.SimpleExecutor#prepareStatement
mybatis之类型处理器_第7张图片
在这里做参数的类型处理,跟进到org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters
mybatis之类型处理器_第8张图片
可以看到这里就是遍历参数,根据参数类型获取对应的类型处理器逐个处理。
再来看下对于数据库查回的结果集是如何做处理的,看下如下逻辑
org.apache.ibatis.executor.statement.PreparedStatementHandler#query
mybatis之类型处理器_第9张图片
这里会调用对应的连接池执行数据库操作,然后进行结果处理。然后直接跟到org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap)
mybatis之类型处理器_第10张图片
这里开始获取对应的行数据,我画红框的地方就是表字段和 Java 类型字段映射处理逻辑,跟进去看下
mybatis之类型处理器_第11张图片
这里又出现了 TypeHandler,这里就是具体的类型处理器对结果进行处理的逻辑。

总结

本文详细介绍了 mybatis 的类型处理器,看完你会发现原来类型处理器实现也是很简单的。

你可能感兴趣的:(mybatis)