mybatis中typehandler配置错误问题分析

457 阅读1分钟

问题描述

配置了mybatis-plus.type-handlers-package后,查询语句从where id = '12345'变成了where id = '"12345"'

问题场景

mapper.xml配置

<select id="getTest" resultMap="testMap">
    select * from test
    <where>
        id = #{id,jdbcType=VARCHAR}
    </where>
</select>

TypeHandler配置

@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JacksonTypeHandler extends BaseTypeHandler<Object> {
  private static ObjectMapper objectMapper = new ObjectMapper();

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setString(i, toJson(parameter));
  }
  protected String toJson(Object obj) {
    try {
      return objectMapper.writeValueAsString(obj);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }
}

问题定位

配置了type-handlers-package后,填充id时使用的是JacksonTypeHandler,导致多了双引号。不配置type-handlers-package时,通过UnknownTypeHandler获取到StringTypeHandler,再次填充id,生成sql正常。

问题分析

mybaits通过SqlSourceBuilder.ParameterMappingTokenHandler#handleToken来解析mapper.xml文件中的#{id,jdbcType=VARCHAR}部分,从中可以解析到property(参数名)、javaType、jdbcType等参数。如例子中,可以得到 property="id", javaType=Object, jdbcType=VARCHAR。

TypeHandlerRegistry通过javaType和jdbcType获取对应的TypeHandler。

  • 如果配置了type-handlers-package,则会注册JacksonTypeHandler,从而取到的TypeHandler就是则会注册的JacksonTypeHandler。
  • 没有配置type-handlers-package的情况下,由于根据javaType=Object, jdbcType=VARCHAR取不到TypeHandler,TypeHandlerRegistry会再次javaType=Object, jdbcType=null取一次,这次取到的是UnknownTypeHandler。

其他

  1. TypeHandlerRegistry的构造函数中注册了常用的TypeHandler。
  2. 同样是获取TypeHandler:TypeHandlerRegistry是通过从mapper.xml文件中解析出的javaType来获取,这里的javaType可以理解为定义的参数类型;UnknownTypeHandler则是通过参数的实际值对应的类型来获取。