全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-20 6 分钟 ✍️ juanwangdev

枚举字段映射

枚举字段映射是将数据库中的枚举字段(字符串或整数)映射为 Java 枚举类型的过程。MyBatis 提供了三种层级的配置方式:全局注册、Mapper XML 字段级指定和注解配置。

数据库枚举字段的两种存储方式

字符串存储(VARCHAR)

idstatuscreated_at
1PENDING2026-05-01 10:00:00
2APPROVED2026-05-02 14:30:00
3REJECTED2026-05-03 09:15:00

对应的 Java 枚举:

Java
public enum ApprovalStatus {
    PENDING, APPROVED, REJECTED
}

整数存储(INT/TINYINT)

idstatuscreated_at
102026-05-01 10:00:00
212026-05-02 14:30:00
322026-05-03 09:15:00

对应同一个枚举,但使用 EnumOrdinalTypeHandler 处理。

方式一:Mapper XML 字段级指定(推荐)

resultMap 中为特定字段指定 TypeHandler:

XML
<resultMap id="approvalResultMap" type="Approval">
    <id column="id" property="id"/>
    <result column="status" property="status"
            typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
    <result column="created_at" property="createdAt"/>
</resultMap>

<select id="selectById" resultMap="approvalResultMap">
    SELECT * FROM approval WHERE id = #{id}
</select>

这种方式可以为单个字段覆盖全局配置,非常灵活。

优先级规则:resultMap 中字段级的 typeHandler 配置优先级最高,参数级次之,mybatis-config.xml 全局注册最低。

方式二:mybatis-config.xml 全局注册

XML
<configuration>
    <typeHandlers>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
                     javaType="com.example.ApprovalStatus"/>
    </typeHandlers>
</configuration>

注册后,所有涉及 ApprovalStatus 的字段都会自动使用 EnumOrdinalTypeHandler,无需在每个 Mapper XML 中重复指定。

方式三:注解配置

Java
@MappedTypes({ApprovalStatus.class})
@MappedJdbcTypes({JdbcType.INTEGER})
public class ApprovalStatusHandler extends BaseTypeHandler<ApprovalStatus> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
            ApprovalStatus status, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, status.ordinal());
    }

    @Override
    public ApprovalStatus getNullableResult(ResultSet rs,
            String columnName) throws SQLException {
        int ordinal = rs.getInt(columnName);
        return rs.wasNull() ? null : ApprovalStatus.values()[ordinal];
    }

    @Override
    public ApprovalStatus getNullableResult(ResultSet rs,
            int columnIndex) throws SQLException {
        int ordinal = rs.getInt(columnIndex);
        return rs.wasNull() ? null : ApprovalStatus.values()[ordinal];
    }

    @Override
    public ApprovalStatus getNullableResult(CallableStatement cs,
            int columnIndex) throws SQLException {
        int ordinal = cs.getInt(columnIndex);
        return cs.wasNull() ? null : ApprovalStatus.values()[ordinal];
    }
}

三种配置方式对比

方式作用范围优先级适用场景
resultMap 字段级指定单个字段最高少数特殊字段需要单独处理
mybatis-config.xml 全局注册全项目最低所有同类型枚举使用统一策略
注解 @MappedTypes全项目中等推荐,配合包扫描自动注册

null 值处理

数据库中的枚举字段可能为 null,TypeHandler 必须正确处理:

Java
@Override
public ApprovalStatus getNullableResult(ResultSet rs,
        String columnName) throws SQLException {
    int ordinal = rs.getInt(columnName);
    if (rs.wasNull()) {
        return null;  // 数据库字段为 null 时返回 Java null
    }
    // ordinal 可能超出枚举范围,需要容错
    ApprovalStatus[] values = ApprovalStatus.values();
    if (ordinal < 0 || ordinal >= values.length) {
        return null;  // 越界视为无效数据
    }
    return values[ordinal];
}

注意:继承 BaseTypeHandler 时,getNullableResult 方法只在非 null 情况下被调用。但如果使用 ResultSet.getInt() 读取整数,null 值会返回 0(Java int 默认值),需要通过 rs.wasNull() 判断。

自定义 code 值映射

当数据库使用自定义 code 值而非枚举名称或索引时:

Java
public enum PaymentMethod {
    ALIPAY("alipay", "支付宝"),
    WECHAT("wechat", "微信支付"),
    BANK_CARD("bankcard", "银行卡");

    private final String code;
    private final String label;

    PaymentMethod(String code, String label) {
        this.code = code;
        this.label = label;
    }

    public String getCode() { return code; }

    public static PaymentMethod fromCode(String code) {
        if (code == null) return null;
        for (PaymentMethod method : values()) {
            if (method.code.equals(code)) {
                return method;
            }
        }
        return null;  // 未知 code 返回 null
    }
}

对应的 TypeHandler:

Java
@MappedTypes({PaymentMethod.class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class PaymentMethodHandler extends BaseTypeHandler<PaymentMethod> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
            PaymentMethod method, JdbcType jdbcType) throws SQLException {
        ps.setString(i, method.getCode());
    }

    @Override
    public PaymentMethod getNullableResult(ResultSet rs,
            String columnName) throws SQLException {
        return PaymentMethod.fromCode(rs.getString(columnName));
    }

    @Override
    public PaymentMethod getNullableResult(ResultSet rs,
            int columnIndex) throws SQLException {
        return PaymentMethod.fromCode(rs.getString(columnIndex));
    }

    @Override
    public PaymentMethod getNullableResult(CallableStatement cs,
            int columnIndex) throws SQLException {
        return PaymentMethod.fromCode(cs.getString(columnIndex));
    }
}

INSERT/UPDATE 中的枚举参数

在 INSERT 或 UPDATE 语句中设置枚举参数:

XML
<!-- 方式一:使用字段级 typeHandler -->
<insert id="insertApproval">
    INSERT INTO approval (status, created_at)
    VALUES (#{status, typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler},
            #{createdAt})
</insert>

<!-- 方式二:全局注册后直接使用 -->
<insert id="insertApproval">
    INSERT INTO approval (status, created_at)
    VALUES (#{status}, #{createdAt})
</insert>

要点总结

  • 数据库枚举字段可存储为字符串(VARCHAR)或整数(INT),分别对应 EnumTypeHandlerEnumOrdinalTypeHandler
  • resultMap 中字段级的 typeHandler 配置优先级最高,允许单个字段覆盖全局配置
  • 全局注册通过 mybatis-config.xml 或注解 @MappedTypes 实现,推荐注解配合包扫描
  • null 值处理需要特别注意:ResultSet.getInt() 的 null 返回 0,必须用 wasNull() 判断
  • 自定义 code 值映射需要在枚举中实现 fromCode() 反查方法和 TypeHandler 的双向转换
  • TypeHandler 配置遵循"就近原则",字段级 > 参数级 > 全局级

📝 发现内容有误?点击此处直接编辑

← 上一篇 TypeHandler 接口
下一篇 → 枚举类型处理
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库