聊聊Mybatis的类型转换接口TypeHandler

504 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

聊聊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是抽象类,具体方法由其他实现类进行实现。