如何获取泛型的class_Mybatis如何实现从javaType至jdbcType?

Mybatis中的TypeHandler有两个功能,一个是完成javaType至jdbcType的转换,另外一个是完成jdbcType至javaType的转换。

public interface TypeHandler {  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;}上面的接口方法,归结起来,其实就是两个方法:setParameter()和

上面的接口方法,归结起来,其实就是两个方法:setParameter()和getResult()。

7972a20d1c7cffe8563cda2b3d2f7a97.png

注意上面的图的箭头方向,跟着箭头方向读,刚好是javaType to jdbcType和jdbcType to javaType。所以,图并没有画错。

说TypeHandler的功能原理,并不是我们的重点,因为大家都懂。我们的重点是,Mybatis如何组织TypeHandler的,以及如何编写一个自定义的TypeHandler,以及TypeHandler是如何“智能”绑定到目标属性的。

1. TypeHandlerRegistry

public final class TypeHandlerRegistry {  // EnumMap,保存Mybatis内部提供的枚举JdbcType类型和对应的TypeHandler  private final Map> JDBC_TYPE_HANDLER_MAP = new EnumMap>(JdbcType.class);    // Type:javaType的Class类型(Type是Class的接口),value是一个Map集合(比如String,可能对应数据库的clob、char、varchar等,所以是一对多关系)  private final Map>> TYPE_HANDLER_MAP = new HashMap>>();    // 处理Object类型(运行时,会尝试进行向下类型转换找到合适的TypeHandler,如果依然失败,最后选择ObjectTypeHandler)  private final TypeHandler UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);    // 所有的TypeHandler. Key:TypeHandler的Class类型,value:TypeHandler实例(都是singleton)  private final Map, TypeHandler>> ALL_TYPE_HANDLERS_MAP = new HashMap, TypeHandler>>();  public TypeHandlerRegistry() {    register(Boolean.class, new BooleanTypeHandler());    register(boolean.class, new BooleanTypeHandler());    register(JdbcType.BOOLEAN, new BooleanTypeHandler());    register(JdbcType.BIT, new BooleanTypeHandler());    register(Byte.class, new ByteTypeHandler());    register(byte.class, new ByteTypeHandler());    register(JdbcType.TINYINT, new ByteTypeHandler());    // ...

Mybatis主要使用Map>> TYPE_HANDLER_MAP,来获取TypeHandler。

下面看看,如何注册一个自定义的TypeHandler。

public class PhoneTypeHandler extends BaseTypeHandler {  @Override  public void setNonNullParameter(PreparedStatement ps, int i, PhoneNumber parameter, JdbcType jdbcType)      throws SQLException {    ps.setString(i, parameter.getAsString());  }  @Override  public PhoneNumber getNullableResult(ResultSet rs, String columnName) throws SQLException {    return new PhoneNumber(rs.getString(columnName));  }  // ...

以上例子,来自于《Java Persistence with MyBatis 3》。

注意代码中的那个泛型参数,虽然没有明确指定PhoneTypeHandler作用于哪一个property上,Mybatis就是依赖泛型参数,获得泛型参数Class对象,再与反射获得的bean属性Class,进行一一对应的。

9a111123017e10b5dbb7bb01d165f23d.png

告诉大家一个秘密,在Spring MVC中,其Converter,就是使用上面的泛型参数与反射原理,从一堆转换器中,准确找到那一个转换器的。

org.apache.ibatis.type.TypeHandlerRegistry.register(TypeHandler)方法源码。

register(typeReference.getRawType(), typeHandler);

上面的getRawType(),就是泛型参数Type类型。Mybatis在启动初始化过程中,会将用户自定义的标签内的所有TypeHandler,注册至Configuration内。

除了上面的“智能”绑定外,我们还可以手动绑定TypeHandler。

手动绑定的TypeHandler优先级较高。

2. 给每一个属性绑定TypeHandler

属性封装,具体对应Mybatis中的ResultMapping或ParameterMapping封装,必须给每一个属性绑定一个TypeHandler。

org.apache.ibatis.mapping.ResultMapping.Builder.resolveTypeHandler()方法源码。ParameterMapping也是类似的,不再重复了。

private void resolveTypeHandler() {      if (resultMapping.typeHandler == null && resultMapping.javaType != null) {        Configuration configuration = resultMapping.configuration;        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();        resultMapping.typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType);      }    }

3. TypeHandler的使用

org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters()方法源码。

TypeHandler typeHandler = parameterMapping.getTypeHandler();typeHandler.setParameter(ps, i + 1, value, jdbcType);

通过TypeHandler转换设置参数。

org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createPrimitiveResultObject()方法源码。

final TypeHandler> typeHandler = rsw.getTypeHandler(resultType, columnName);return typeHandler.getResult(rsw.getResultSet(), columnName);

通过TypeHandler转换获取结果。

以上便是Mybatis中,有关TypeHandler的内容,一般情况下,我们不需要自定义TypeHandler,Mybatis内置了大多数常见的TypeHandler。只有Mybatis不能满足复杂类型转换时,我们才考虑自定义。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值