23. 如何在MyBatis中处理枚举类型?有哪些常见的处理方式?
在 MyBatis 中,处理枚举类型有多种方式,通常取决于枚举在数据库中的存储形式以及你希望在 Java 中如何使用这些枚举类型。常见的处理方式包括使用 EnumTypeHandler
、自定义 TypeHandler
,或通过直接在枚举中定义转换方法来实现。
1. 使用 MyBatis 内置的 EnumTypeHandler
MyBatis 提供了内置的 EnumTypeHandler
,可以用于将枚举类型映射为数据库中的整数或字符串。
1.1 枚举类型映射为字符串
假设你有一个枚举 Status
,希望将其映射为数据库中的字符串:
public enum Status {
ACTIVE, INACTIVE, DELETED;
}
对应的数据库表结构:
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(50),
status VARCHAR(10) -- 存储枚举值的字符串形式
);
在 MyBatis 中,你可以使用 EnumTypeHandler
自动处理这个映射:
配置 EnumTypeHandler
:
你可以在 mybatis-config.xml
中全局配置 EnumTypeHandler
:
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumTypeHandler" javaType="com.example.Status" jdbcType="VARCHAR"/>
</typeHandlers>
或者在 Mapper
文件中为特定字段配置 EnumTypeHandler
:
<select id="selectUserById" resultType="User">
SELECT id, name, status
FROM user
WHERE id = #{id}
</select>
<resultMap id="UserResultMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="status" column="status" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
在这种情况下,MyBatis 会将数据库中的字符串值自动映射到对应的 Status
枚举类型。
1.2 枚举类型映射为整数
如果你希望将枚举映射为整数,可以在枚举中定义数值,然后使用 EnumOrdinalTypeHandler
:
public enum Status {
ACTIVE(1), INACTIVE(2), DELETED(3);
private final int value;
Status(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
对应的数据库表结构:
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(50),
status INT -- 存储枚举值的整数形式
);
配置 EnumOrdinalTypeHandler
:
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.example.Status" jdbcType="INTEGER"/>
</typeHandlers>
这会将枚举的 ordinal 值(即枚举在定义中的顺序)存储到数据库,并在查询时将整数转换回枚举类型。
2. 使用自定义 TypeHandler
如果你有更复杂的需求,比如枚举对应的数据库值并不是 ordinal
或 name
,而是自定义的某个值(如数据库中的状态码),你可以自定义一个 TypeHandler
来处理这些映射。
示例:自定义 TypeHandler
映射枚举到状态码
假设你有一个 Status
枚举,它对应的数据库字段是一个状态码,而不是 ordinal
或 name
:
public enum Status {
ACTIVE(1), INACTIVE(0), DELETED(-1);
private final int code;
Status(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static Status fromCode(int code) {
for (Status status : Status.values()) {
if (status.getCode() == code) {
return status;
}
}
throw new IllegalArgumentException("Unknown status code: " + code);
}
}
创建自定义 TypeHandler
:
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.*;
public class StatusTypeHandler extends BaseTypeHandler<Status> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Status status, JdbcType jdbcType) throws SQLException {
ps.setInt(i, status.getCode());
}
@Override
public Status getNullableResult(ResultSet rs, String columnName) throws SQLException {
int code = rs.getInt(columnName);
return Status.fromCode(code);
}
@Override
public Status getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
int code = rs.getInt(columnIndex);
return Status.fromCode(code);
}
@Override
public Status getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
int code = cs.getInt(columnIndex);
return Status.fromCode(code);
}
}
注册自定义 TypeHandler
:
在 mybatis-config.xml
中注册自定义的 TypeHandler
:
<typeHandlers>
<typeHandler handler="com.example.StatusTypeHandler" javaType="com.example.Status" jdbcType="INTEGER"/>
</typeHandlers>
在 Mapper
中使用自定义 TypeHandler
:
<resultMap id="UserResultMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="status" column="status" typeHandler="com.example.StatusTypeHandler"/>
</resultMap>
3. 通过枚举类本身处理映射
另一种方式是在枚举类中直接定义用于数据库存储的值,并提供从数据库值到枚举实例的转换方法。这种方式使得枚举的映射逻辑集中在枚举类中,简化了 TypeHandler
的使用。
示例:
public enum Status {
ACTIVE(1), INACTIVE(0), DELETED(-1);
private final int code;
Status(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static Status fromCode(int code) {
for (Status status : Status.values()) {
if (status.getCode() == code) {
return status;
}
}
throw new IllegalArgumentException("Unknown status code: " + code);
}
}
在 Mapper
XML 文件中直接使用 #{status.code}
:
<insert id="insertUser" parameterType="User">
INSERT INTO user (id, name, status)
VALUES (#{id}, #{name}, #{status.code})
</insert>
<select id="selectUserById" resultMap="UserResultMap">
SELECT id, name, status
FROM user
WHERE id = #{id}
</select>
在这个例子中,MyBatis 会自动调用 Status
枚举的 getCode()
方法来获取数据库中存储的值,然后使用 fromCode()
方法将数据库值转换回枚举实例。
总结
EnumTypeHandler
和EnumOrdinalTypeHandler
:MyBatis 内置的处理器,适用于枚举映射为字符串或整数的情况。- 自定义
TypeHandler
:当你需要更复杂的映射逻辑时,自定义TypeHandler
是一个灵活的解决方案。 - 在枚举类中处理映射:通过在枚举类中定义用于数据库存储的值和从数据库值转换回枚举的方法,可以简化 MyBatis 映射配置。
根据具体的需求和场景,可以选择最适合的方式来处理枚举类型在 MyBatis 中的映射。