在MyBatis开发中,枚举类型与数据库整形字段的映射是常见需求,默认的枚举映射逻辑往往无法适配业务自定义的存储规则,比如很多业务会将枚举的自定义编码存入数据库整形字段,而非枚举的 ordinal 或者 name,这时候就需要通过实现自定义TypeHandler来完成映射。

默认枚举映射的局限性
MyBatis对枚举类型有默认的映射处理,默认情况下,如果枚举字段没有指定TypeHandler,会根据枚举的 ordinal 值(枚举定义的顺序,从0开始)或者 name 值(枚举的名称字符串)与数据库字段映射。但很多业务场景中,枚举会有一个自定义的整形编码,比如订单状态枚举,可能有待支付编码1、已支付编码2、已取消编码3,这些编码和枚举的 ordinal 不一定一致,默认的映射方式就无法满足需求,这时候就需要自定义TypeHandler。
自定义TypeHandler实现步骤
1. 定义枚举类
首先定义需要映射的枚举,给每个枚举项添加自定义的整形编码,同时提供根据编码获取枚举实例的方法。
public enum OrderStatusEnum {
UNPAID(1, "待支付"),
PAID(2, "已支付"),
CANCELED(3, "已取消");
private final int code;
private final String desc;
OrderStatusEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
// 根据编码获取枚举实例
public static OrderStatusEnum getByCode(int code) {
for (OrderStatusEnum status : OrderStatusEnum.values()) {
if (status.getCode() == code) {
return status;
}
}
throw new IllegalArgumentException("无效的订单状态编码: " + code);
}
}
2. 实现自定义TypeHandler
MyBatis的TypeHandler需要实现org.apache.ibatis.type.TypeHandler接口,或者继承org.apache.ibatis.type.BaseTypeHandler抽象类,后者已经实现了大部分通用逻辑,我们只需要重写核心方法即可。需要实现的方法有四个,分别对应参数设置、结果集读取的不同场景。
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class OrderStatusEnumTypeHandler extends BaseTypeHandler<OrderStatusEnum> {
// 设置参数时,将枚举的编码存入数据库整形字段
@Override
public void setNonNullParameter(PreparedStatement ps, int i, OrderStatusEnum parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getCode());
}
// 从结果集按列名读取时,根据整形值转换为枚举
@Override
public OrderStatusEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
int code = rs.getInt(columnName);
// 如果数据库字段为null,返回null
if (rs.wasNull()) {
return null;
}
return OrderStatusEnum.getByCode(code);
}
// 从结果集按列索引读取时,根据整形值转换为枚举
@Override
public OrderStatusEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
int code = rs.getInt(columnIndex);
if (rs.wasNull()) {
return null;
}
return OrderStatusEnum.getByCode(code);
}
// 从存储过程读取时,根据整形值转换为枚举
@Override
public OrderStatusEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
int code = cs.getInt(columnIndex);
if (cs.wasNull()) {
return null;
}
return OrderStatusEnum.getByCode(code);
}
}
3. 注册TypeHandler
自定义TypeHandler完成后,需要在MyBatis的配置文件中注册,让MyBatis能够识别并使用它。注册方式有两种,一种是全局注册,一种是局部指定。
全局注册
在MyBatis的配置文件mybatis-config.xml中添加typeHandlers配置,指定自定义TypeHandler的全类名,这样所有OrderStatusEnum类型的字段都会默认使用这个TypeHandler。
<configuration>
<typeHandlers>
<typeHandler handler="com.example.handler.OrderStatusEnumTypeHandler"/>
</typeHandlers>
</configuration>
局部指定
如果不想全局注册,也可以在映射文件的具体字段上指定TypeHandler,比如在resultMap中指定jdbcType和typeHandler,或者在insert/update语句的参数上指定。
<resultMap id="orderResultMap" type="com.example.entity.Order">
<id column="id" property="id"/>
<result column="order_status" property="orderStatus" typeHandler="com.example.handler.OrderStatusEnumTypeHandler"/>
</resultMap>
<insert id="insertOrder" parameterType="com.example.entity.Order">
INSERT INTO orders (order_no, order_status)
VALUES (#{orderNo}, #{orderStatus, typeHandler=com.example.handler.OrderStatusEnumTypeHandler})
</insert>
使用效果验证
完成上述配置后,当插入订单数据时,OrderStatusEnum类型的orderStatus字段会自动将其code值存入数据库的整形字段order_status;当查询订单数据时,数据库中的整形值会自动转换为对应的OrderStatusEnum枚举实例,无需手动做转换处理,大大提升了开发效率。
如果后续有新的枚举类型需要和整形字段映射,只需要按照同样的步骤,定义新的枚举类和对应的TypeHandler即可,复用性很强。需要注意的是,枚举的getByCode方法要做好异常处理,避免出现无效的编码导致程序报错。
MyBatisTypeHandler枚举类型映射数据库整形字段修改时间:2026-07-16 09:12:28