背景
MyBatis查询若想映射枚举类型,则需要从 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中选一个来使用
是按照序列来存取的,对应数据库的设计为 使用0开始按升序。
是按照枚举的名字来存取的,对应数据库的设计为 直接使用枚举名。
但是也有存在不是按0开始的,也不是按0升序的情况。上面两个都不满足我们的需求, 这时候又想使用枚举这就需要使用自定义枚举类。
使用
可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler
IEnum.java
/**
*
* @ClassName: IEnum
* @Description: 本系统所有枚举实现的接口 规范key value 用于MyBatis枚举映射
* @author jerome_s@qq.com
* @date 2015年11月29日 下午9:29:35
*
*/
publicinterfaceIEnum {
intgetKey();
voidsetKey(intkey);
String getValue();
voidsetValue(String value);
}
EnumKeyTypeHandler.java
/**
*
* @ClassName: EnumKeyTypeHandler
* @Description: 本系统所有枚举都是使用这个处理器将key定为存取的依据
* @author jerome_s@qq.com
* @date 2015年11月29日 下午9:34:14
* @see 参考源码EnumOrdinalTypeHandler/EnumTypeHandler
* @see 参考 http://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers
*
*/
publicclassEnumKeyTypeHandler extendsBaseTypeHandler<IEnum>{
privateClass<IEnum> type;
privatefinalIEnum[] enums;
/**
* 设置配置文件设置的转换类以及枚举类内容,供其他方法更便捷高效的实现
* @param type 配置文件中设置的转换类
*/
publicEnumKeyTypeHandler(Class<IEnum> type) {
if(type == null)
thrownewIllegalArgumentException("Type argument cannot be null");
this.type = type;
this.enums = type.getEnumConstants();
if(this.enums == null)
thrownewIllegalArgumentException(type.getSimpleName()
+ " does not represent an enum type.");
}
@Override
publicIEnum getNullableResult(ResultSet rs, String columnName) throwsSQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放INT类型
inti = rs.getInt(columnName);
if(rs.wasNull()) {
returnnull;
} else{
// 根据数据库中的code值,定位IEnum子类
returnlocateIEnum(i);
}
}
@Override
publicIEnum getNullableResult(ResultSet rs, intcolumnIndex) throwsSQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放INT类型
inti = rs.getInt(columnIndex);
if(rs.wasNull()) {
returnnull;
} else{
// 根据数据库中的code值,定位IEnum子类
returnlocateIEnum(i);
}
}
publicIEnum getNullableResult(CallableStatement cs, intcolumnIndex) throwsSQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放INT类型
inti = cs.getInt(columnIndex);
if(cs.wasNull()) {
returnnull;
} else{
// 根据数据库中的code值,定位IEnum子类
returnlocateIEnum(i);
}
}
publicvoidsetNonNullParameter(PreparedStatement ps, inti, IEnum parameter, JdbcType jdbcType)
throwsSQLException {
// baseTypeHandler已经帮我们做了parameter的null判断
ps.setInt(i, parameter.getKey());
}
/**
* 枚举类型转换,由于构造函数获取了枚举的子类enums,让遍历更加高效快捷
* @param key 数据库中存储的自定义code属性
* @return code对应的枚举类
*/
privateIEnum locateIEnum(intkey) {
for(IEnum status : enums) {
if(status.getKey()== key) {
returnstatus;
}
}
thrownewIllegalArgumentException("未知的枚举类型:"+ key + ",请核对"+ type.getSimpleName());
}
}
SexEnum.java
/**
* 性别枚举
*
* @author jerome_s@qq.com
*/
publicenumSexEnum implementsIEnum {
MAN(1, "男"), WOMAN(2, "女");
privateintkey;
privateString value;
privateSexEnum(intkey, String value) {
this.key = key;
this.value = value;
}
publicintgetKey() {
returnkey;
}
publicvoidsetKey(intkey) {
this.key = key;
}
publicString getValue() {
returnvalue;
}
publicvoidsetValue(String value) {
this.value = value;
}
}
dao
List<User> users = sqlSession.selectList("UserMapper.selectUsers4Enum");
for(User u : users) {
System.out.println(u.toString());
}
mapper
<resultMapid="selectUsers4EnumResultMap"type="User">
<resultproperty="sex"column="sex"javaType="com.hqu.enums.SexEnum"typeHandler="com.hqu.enums.EnumKeyTypeHandler"/>
</resultMap>
<selectid="selectUsers4Enum"resultMap="selectUsers4EnumResultMap">
SELECT * FROM t_user
</select>
结果
User [id=1, user_name=jerome100, age=26, sex=MAN, birthday=Sat Dec 31 00:00:00 CST 2016]
User [id=3, user_name=jelly, age=25, sex=WOMAN, birthday=Sat Dec 31 00:00:00 CST 2016]
User [id=4, user_name=jerome, age=26, sex=MAN, birthday=Sat Dec 31 00:00:00 CST 2016]
User [id=5, user_name=jelly, age=25, sex=WOMAN, birthday=Sat Dec 31 00:00:00 CST 2016]
总结
个人觉得有关MyBatis的插入查询更新等还是不用枚举的好因为会增加复杂度和代码量,使用数字代表的较为合理。
参考:
1. mybatis官方文档
2. EnumTypeHandler和EnumOrdinalTypeHandler的区别
3. 自定义枚举类参考
4. MyBatis官方手册