问题描述
配置了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。
其他
- TypeHandlerRegistry的构造函数中注册了常用的TypeHandler。
- 同样是获取TypeHandler:TypeHandlerRegistry是通过从mapper.xml文件中解析出的javaType来获取,这里的javaType可以理解为定义的参数类型;UnknownTypeHandler则是通过参数的实际值对应的类型来获取。