MyBatis ResultType使用自定义TypeHandler

本文介绍了在MyBatis中,使用ResultType时自定义TypeHandler无法生效的问题。作者通过分析源码,发现配置JavaType和JdbcType可能导致MyBatis无法找到自定义TypeHandler。解决方案是正确配置JavaType和JdbcType,以确保使用自定义TypeHandler进行数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、背景

最近在使用MyBatis自定义的TypeHandler在对数据做基础加工,在对ResultMap使用自定义TypeHandler时是没有问题的,可以正常进入TypeHandler中处理数据,但是当结果集被定义为ResultType时总是不进入自定义的TypeHandler,基于这个情况,不得不再次打开MyBatis的源码一探究竟

2、基础代码

/**
 * 自定义TypeHandler
 *
 * @author fulibao
 * @version 1.0
 * @created 2017/7/10 下午4:29
 **/
public class SecurityStringVarcharTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        //自定义代码

        return rs.getString(columnName);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        //自定义代码

        return rs.getString(columnIndex);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        //自定义代码

        return cs.getString(columnIndex);
    }
}

MyBatis XML配置文件:

<select id="getByApplicationIds" parameterType="list" resultType="censorModel">
    <include refid="getAll"/>
    where application_id in
    <foreach collection="list" item="applicationId" index="index"
             open="(" close=")" separator=",">
        #{applicationId}
    </foreach>
</select>

mybatis-config.xml中对于typeHandler的配置

<typeHandlers>
    <typeHandler jdbcType="VARCHAR" javaType="java.lang.String"
                 handler="com.meituan.fd.crm.common.typehandler.SecurityStringVarcharTypeHandler"/>
</typeHandlers>

3、问题排查

3.1、MyBatis执行查询等操作的基础类为:DefaultSqlSession,其代码为:

public <T> T selectOne(String statement) {
  return this.<T>selectOne(statement, null);
}

public <T> T selectOne(String statement, Object parameter) {
  // Popular vote was to return null on 0 results and throw exception on too many.
  List<T> list = this.<T>selectList(statement, parameter);
  if (list.size() == 1) {
    return list.get(0);
  } else if (list.size() > 1) {
    throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
  } else {
    return null;
  }
}

public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
  return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
}

public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
  return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
}

public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
  final List<?> list = selectList(statement, parameter, rowBounds);
  final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
      configuration.getObjectFactory(), configuration.getObjectWrapperFactory());
  final DefaultResultContext context = new DefaultResultContext();
  for (Object o : list) {
    context.nextResultObject(o);
    mapResultHandler.handleResult(context);
  }
  Map<K, V> selectedMap = mapResultHandler.getMappedResults();
  return selectedMap;
}

public <E> List<E> selectList(String statement) {
  return this.selectList(statement, null);
}

public <E> List<E> selectList(String statement, Object parameter) {
  return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    return result;
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

可以看到无论是selectOne、selectMap、selectList最终调用的都是selectList方法,因此我们由selectList入手开始排查问题。

public &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值