X

如何在Mybatis注解中使用枚举类型

当下我们都在使用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】

Categories: Java学习 其他
龙安_任天兵: 不忘初心,方得始终!

View Comments (1)