Mybatis 源码学习-类型转换(TypeHandler)
Posted 凉茶方便面
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis 源码学习-类型转换(TypeHandler)相关的知识,希望对你有一定的参考价值。
历史文章:
Mybatis 源码学习(7)-反射工具(ObjectWrapper & MetaObject)
JDBC 规范中定义的数据类型和 Java语言中的数据类型并非完全对应,因此需要在操作 Statement 时需要将 Java 类型转为 JDBC 类型,而处理 Result时,需要将JDBC 类型,转为 Java 类型。Mybatis 使用 TypeHandler 处理这种类型转换逻辑,另外 Mybatis 使用 JdbcType 枚举了所有的 JDBC类型,并将 JDBC 规范中的原始数值作为 TYPE_CODE,构造出 codeLookup 作为 code 和枚举的映射 Map。
Mybatis 中存在多个 TypeHandler 的子类,并且提供 BaseTypeHandler 作为默认实现,由具体子类继承实现具体的逻辑,但是大部分子类都会直接使用 Statement 的对应方法。
TypeHandler 提供了四个方法,其中:setParameter 负责将 JdbcType 转为 Java 类型;三个重载的 getResult 负责将数据由 Java 类型转为 JdbcType。
public interface TypeHandler<T>
// 通过 PreparedStatement 为 SQL 语句绑定参数,将 Java 类型转为 JDBC 数据
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
// 通过 Statement 获取指定列的值,将数据从 JDBC 数据转为 Java 类型
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
从继承关系可知,除了 TypeHandler 外,Mybatis 还提供了 BaseTypeHandler 作为基类,它实现 TypeHandler 接口并继承 TypeReference 抽象类。
BaseTypeHandler 实现了基本的 setParameter 和 getResult 方法,它们都可以以默认方式处理 null 的情况,但是非 null 的情况交给了具体实现类处理。
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException
// 参数是 null
if (parameter == null)
if (jdbcType == null)
throw new TypeException(“…”);
try
// 直接按照 Jdbc 类型的 null 存储
ps.setNull(i, jdbcType.TYPE_CODE);
catch (SQLException e)
throw new TypeException(“…”);
else
try
// 处理非 null,由具体子类实现
setNonNullParameter(ps, i, parameter, jdbcType);
catch (Exception e)
throw new TypeException(“…”);
public T getResult(ResultSet rs, String columnName) throws SQLException
T result;
try
// 获取允许为 null 的结果集,由具体子类实现
result = getNullableResult(rs, columnName);
catch (Exception e)
throw new ResultMapException(“…");
if (rs.wasNull())
return null;
else
return result;
由于 BaseTypeHandler 的实现类较多,因此以 IntegerTypeHandler 为例说明具体子类的实现方式。
public class IntegerTypeHandler extends BaseTypeHandler<Integer>
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
throws SQLException
ps.setInt(i, parameter); // 直接使用 Statement 的方法
@Override
public Integer getNullableResult(ResultSet rs, String columnName)
throws SQLException
return rs.getInt(columnName); // 直接使用 ResultSet 的方法,获取指定列的值
@Override
public Integer getNullableResult(ResultSet rs, int columnIndex)
throws SQLException
return rs.getInt(columnIndex);
@Override
public Integer getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException
return cs.getInt(columnIndex);
总结
TypeHandler 可以实现 Java 类型到 JDBC 类型之间的转换,它提供了默认的基类,但是具体的非空数据的转换交由子类实现。另外,TypeHandler 仅用于处理单列数据的转换,对于复杂数据类型的转化,可以使用 <resultMap>
进行映射。
参考文档:《Mybatis 技术内幕》
本文的基本脉络参考自《Mybatis 技术内幕》,编写文章的原因是希望能够系统地学习 Mybatis 的源码,但是如果仅阅读源码或者仅从官方文档很难去系统地学习,因此希望参考现成的文档,按照文章的脉络逐步学习。
欢迎关注我的公众号:我的搬砖日记,我会定时分享自己的学习历程。
以上是关于Mybatis 源码学习-类型转换(TypeHandler)的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis 源码学习(10)-类型转换(TypeAliasRegistry)
Mybatis 源码学习(10)-类型转换(TypeAliasRegistry)
Mybatis 源码学习-类型转换(TypeHandler)
Mybatis 源码学习-类型转换(TypeHandler)