聊聊 Mybatis 的类型转换接口 TypeHandler
mybatis 可以实现 jdbc 类型和 java 类型之间的转换,具体来说有一个类型转换器的接口:
类型处理器接口 TypeHandler
TypeHandler 接口的定义如下:
public interface TypeHandler<T> {
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
复制代码
接口中定义了设置参数的方法和获取结果的方法,根据参数不同定义了三种获取结果的方法,这是 Java 多态的体现,而接口的定义和方法的定义都使用了泛型。
类型处理器 BaseTypeHandler
jdbc 类型转为 java 类型
BaseTypeHandler 类实现了 TypeHandler 接口,实现了 setParameter()方法
这是 BaseTypeHandler 类的 setParameter()方法的实现逻辑:
@Override
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 e) {
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: " + e, e);
}
} else {
try {
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
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: " + e, e);
}
}
}
复制代码
这个方法看着很长,其实逻辑非常的简单,方法中就是设置 PreparedStatement 的参数,也是参数绑定,将 jdbcType 转为 Java 类型,setNonNullParameter 是抽象方法,根据不同的参数类型有不同的类实现了这个方法,比如 LongTypeHandler 实现的 setNonNullParameter()方法:
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType)
throws SQLException {
ps.setLong(i, parameter);
}
复制代码
java 类型转为 jdbc 类型
BaseTypeHandler 类作为 TypeHandler 接口的基础实现类,它同样实现了获取转换后的结果的方法。BaseTypeHandler 类的 getResult()方法:
@Override
public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
try {
return getNullableResult(cs, columnIndex);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement. Cause: " + e, e);
}
}
复制代码
方法也比较简单,直接调用了 getNullableResult 抽象类,功能就是从 ResultSet 中获取数据,把 Java 类型转换为 JdbcType 类型,比如 LongTypeHandler 实现的 getNullableResult():
@Override
public Long getNullableResult(ResultSet rs, String columnName)
throws SQLException {
long result = rs.getLong(columnName);
return result == 0 && rs.wasNull() ? null : result;
}
复制代码
这一块的逻辑和设置参数的方法整体逻辑是差不多的,整体思想有种模板方法设计模式的设计思想
通过源码分析我们知道了 TypeHandler 接口的作用就是用来实现类型转换的,mybatis 在初始化的时候就获取 TypeHandler,然后创建 TypeHandler 实例注册到 TypeHandlerRegistry 中,由 TypeHandlerRegistry 来进行管理这些实例,下篇文章中我们介绍一下 TypeHandlerRegistry 这个类
总结
这篇文章讲了 Mybatis 的类型转换接口 TypeHandler 和它的实现类 BaseTypeHandler,类型转换接口显然就是实现 jdbc 类型和 java 类型之间的转换,同时分析了 BaseTypeHandler 的 setParameter()方法和 getResult()方法,getNullableResult 是抽象类,具体方法由其他实现类进行实现。
评论