mybatis 中 java 枚举与数据库整型字段的无感转换需通过 typehandler 实现:核心是自定义继承 basetypehandler 的泛型处理器(如 enumcodetypehandler),利用枚举的 getcode() 和 of(int) 方法完成双向转换,并支持空值容错与全局/局部注册。

Java 枚举在 MyBatis 中不能直接存取数据库,必须通过类型处理器(TypeHandler)明确告诉框架“怎么把枚举转成数据库值、怎么从数据库值还原枚举”。核心不是写一堆反射代码,而是选对方式、写清逻辑、注册到位。
用 @EnumValue 注解快速映射(适合简单场景)
MyBatis 3.4.0+ 支持在枚举里用 @EnumValue 标记一个 getter 方法,框架会自动用它的返回值做读写。前提是这个方法返回类型和数据库字段类型一致(比如 String 对应 VARCHAR,int 对应 TINYINT)。
- 枚举中必须有带
@EnumValue的 public getter,例如getCode()或getValue() - 反向查找需手动提供静态方法(如
fromCode(String)),MyBatis 不自动调用它,只靠构造器参数匹配——所以推荐枚举构造器参数顺序与@EnumValue方法返回值一致 - 不支持 null 值或非法值兜底,出错时直接抛
IllegalArgumentException
写自定义 TypeHandler 实现双向控制(推荐主流做法)
继承 BaseTypeHandler
-
setNonNullParameter():把枚举的码值(如status.getCode())设进PreparedStatement -
getNullableResult()(两个重载):从ResultSet读出数据库值,用枚举自带的查找方法(如OrderStatus.of(2))转成枚举对象 - 务必在
getNullableResult中判断 null 和非法值,返回默认项(如UNKNOWN)或抛定制异常,避免运行时崩溃 - 泛型写法可复用,比如
EnumCodeTypeHandler<orderstatus></orderstatus>能减少重复代码
注册 TypeHandler 的三种方式
写了处理器还不算完,得让 MyBatis “看见”它。三种注册方式按优先级递减:
-
局部指定最清晰:在 Mapper XML 的
<resultmap></resultmap>或 SQL 标签里用typeHandler属性,例如:<result property="status" column="status_code" typehandler="com.example.OrderStatusTypeHandler"></result> -
包扫描最省事:在
application.yml或mybatis-config.xml中配置type-handlers-package,MyBatis 自动扫描该包下所有 TypeHandler -
全局注册最彻底:在 MyBatis 配置中显式声明
<typehandler handler="xxx.TypeHandler"></typehandler>,适用于跨模块复用
避坑要点
实际开发中容易忽略但影响稳定的几个细节:
- 别用
ordinal()映射——枚举顺序一变,数据库数据就错乱;优先用稳定字段如code或value - 数据库字段类型要匹配:String 枚举对应 VARCHAR,int 枚举对应 TINYINT/INT,类型不一致会报 JDBC 异常
- TypeHandler 类必须有无参构造函数,否则 Spring 无法注入
- 如果用了 MyBatis-Plus,它自带
EnumTypeHandler,但仅支持name()或ordinal(),复杂业务仍建议自己写
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











