当下我们都在使用spring boot,配合注解的使用,我们彻底抛弃了xml的配置。在使用spring boot mybatis的时候,关于使用spring boot mybatis注解使用的文档却不清不楚。官网大部分的例子和使用都是叫你如何写mapper.xml。很多时候,一些特别的需求关于注解如何实现这个功能都是一句话带过,很多地方连一句话都没有。在使用spring boot mybatis的过程中,我遇到过很多特殊的需求。例如动态sql的使用,通过插件来注入修改用户的sql语句,枚举类型的使用等。很多case当时搞明白了,过了段时间再用又忘记了,去寻找解决方法的时候又没有靠谱答案,所以这里把用过的一些case写一个序列的文章,方便自己和后来者。
这篇文章是关于mybatis使用注解处理枚举类型的情况。很多时候,我们定义一个类型的时候数据库里存储的往往是int类型,而我们希望在代码中还是能保持和使用枚举类型,这个时候就要针对枚举类型做出一些处理了。官网关于使用xml的时候处理枚举类型描述[文档](http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers)。 举例说明,我们有一个描述数据类型的枚举类。
public enum ConfigType { STRING(1), BOOLEAN(2), OTHER(3); private int type; ConfigType(int type) { this.type = type; } public int getType() { return type; } public void setType(int type) { this.type = type; } public static ConfigType getType(int type) { if (1 == type) { return STRING; } else if (2 == type) { return BOOLEAN; } return OTHER; } }
然而在我们数据的字段设计的时候, 这个type字段存储的是int类型。这个时候我们直接在mapper里写入的时候,就会出错, 因为ConfigInfo里定义的type是ConfigType的枚举类型, 而数据库是int类型,他当然不知道怎么办了。ps,如果你的数据库存储的是String类型,他会把枚举的name存储进去.
@Insert("insert into config_info (gmt_create, gmt_modified, user_id, name, type) values (now(),now(),#{userId},#{name},#{type})") int saveConfigInfo(ConfigInfo infoDO);
为什么会把枚举的名称存储进去呢? 以为默认的枚举处理是使用EnumTypeHandler(还有其他一大票的handler把JavaType转成jdbcType), MyBatis 会利用 EnumTypeHandler 来把 Enum 值转换成对应的名字。
那么如果我们要转成整型怎么办呢? 使用EnumOrdinalTypeHandler,将上面的insert语句修改如下
@Insert("insert into config_info (gmt_create, gmt_modified, user_id, name, type) values (now(),now(),#{userId},#{name},#{type,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler})") int saveConfigInfo(ConfigInfo infoDO);
org.apache.ibatis.parsing.GenericTokenParser这个类在处理的时候,就会使用这个类处理枚举类。他是使用的枚举的索引(下标从0开始)来转换的数字。这样做有个弊端。数据和位置强耦合,代码里还看不到,调整下顺序你以为没问题,结果全挂了,风险大。
所以我们应该如何自定义枚举的抓换逻辑呢? 你得定义一个自己的handler
public class ConfigTypeEnumHandler extends BaseTypeHandler<ConfigType> { public void setNonNullParameter(PreparedStatement ps, int i, ConfigType parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.getType()); } public ConfigType getNullableResult(ResultSet rs, String columnName) throws SQLException { int type = rs.getInt(columnName); if (rs.wasNull()) { return null; } else { return ConfigType.getType(type); } } public ConfigType getNullableResult(ResultSet rs, int columnIndex) throws SQLException { int type = rs.getInt(columnIndex); if (rs.wasNull()) { return null; } else { return ConfigType.getType(type); } } public ConfigType getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { int type = cs.getInt(columnIndex); if (cs.wasNull()) { return null; } else { return ConfigType.getType(type); } } }
然后将你的mapper里面的handler改成自己的,这样的枚举类型你可以自由决定取用哪个字段。
@Insert("insert into config_info (gmt_create, gmt_modified, user_id, name, type) values (now(),now(),#{userId},#{name},#{type,typeHandler=your.package.name. ConfigTypeEnumHandler})") int saveConfigInfo(ConfigInfo infoDO);
下一篇【动态sql】
下一篇【使用插件实现注入用户sql】
真是学无止境!