迁移之前的老项目的时候,老项目中使用了一些MyBatis的TypeHandler相关的东西。但是老项目并非写在mapper.xml文件里面,而是使用@Select注解,把SQL写在了一个Class中。
在改造的过程中,我将TypeHandler迁移到了xml文件中,然后报了一些错误,比如:
Type handler was null on parameter mapping for property 'xxx'.
再比如:
ClassNotFound:com.xxx.XXXTypeHandler
解决时间也不算太长,但是还是记录一下,方便出现这类问题的人或者自己下次使用。
其实不管出现什么问题,肯定是TypeHandler没有配置好,所以我们直接说一下MyBatis的TypeHandler要怎么配置。
- 先看一下需要用到TypeHandler的实体类:
@Data
public class MyConfig implements Serializable {
private Long id;
private DetailJson detail;
}
- 然后是TypeHandler类:
public class MyConfigDetailJsonHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, DetailJson parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public DetailJson getNullableResult(ResultSet rs, String columnName) throws SQLException {
String string = rs.getString(columnName);
if(StringUtils.isBlank(string) || !string.startsWith("{") || !string.endsWith("}")) {
return null;
}
DetailJson javaObject = JSON.toJavaObject(JSON.parseObject((rs.getString(columnName))), DetailJson.class);
return javaObject;
}
@Override
public DetailJson getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return null;
}
@Override
public DetailJson getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return null;
}
}
- mapper.xml文件中的写法:
- resultMap:
- select:
- insert:
insert into my_config (id, detail)
values (#{id,jdbcType=BIGINT}, #{detail,jdbcType=VARCHAR})
这里需要注意,TypeHandler只在resultMap中写就可以了,insert和update语句不需要写,否则会报错。
上述代码能简化就简化了,像select * 这种并不是提倡的写法。
- 配置数据库Factory的时候,把TypeHandler所在的路径配上,也可以直接配置TypeHandler类:
- 配置TypeHandler路径:
@Primary
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTypeHandlersPackage("com.abc.typehandler");
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
return bean.getObject();
}
- 直接配置TypeHandler:
@Primary
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTypeHandlers(new MyConfigDetailJsonHandler());
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
return bean.getObject();
}