MyBatis?枚舉映射的實(shí)現(xiàn)示例
一、MyBatis 枚舉映射四大實(shí)現(xiàn)方案
1. 基礎(chǔ)序數(shù)映射(EnumTypeHandler)
// Java 枚舉類
public enum OrderStatus {
NEW, PAID, DELIVERED, CANCELLED;
}
// MyBatis實(shí)體類映射
public class Order {
private OrderStatus status;
// getters/setters
}??Mapper XML 配置??:
<resultMap id="orderResultMap" type="Order">
<result property="status" column="status"/>
</resultMap>??MySQL 表設(shè)計(jì)??:
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
status TINYINT COMMENT '0-新訂單,1-已支付,2-已發(fā)貨,3-已取消'
);??優(yōu)缺點(diǎn)??:
- ? 零配置自動生效
- ?? 無法修改枚舉順序
- ?? 數(shù)據(jù)庫可讀性差
2. 枚舉名稱映射(EnumOrdinalTypeHandler)
// MyBatis 配置文件
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumTypeHandler"
javaType="com.example.OrderStatus"/>
</typeHandlers>
// 或全局配置
<settings>
<setting name="defaultEnumTypeHandler"
value="org.apache.ibatis.type.EnumTypeHandler"/>
</settings>??表設(shè)計(jì)??:
ALTER TABLE orders MODIFY COLUMN status VARCHAR(20) COMMENT '訂單狀態(tài)';
??適配枚舉改動??:
public enum OrderStatus {
NEW("新訂單"),
PAID("已支付"),
DELIVERED("已發(fā)貨"),
CANCELLED("已取消");
private final String desc;
OrderStatus(String desc) {
this.desc = desc;
}
}3. 自定義類型處理器(TypeHandler)
3.1 基于字符串的轉(zhuǎn)換
@MappedTypes(OrderStatus.class)
public class OrderStatusHandler extends BaseTypeHandler<OrderStatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
OrderStatus status, JdbcType jdbcType) {
ps.setString(i, status.name());
}
@Override
public OrderStatus getNullableResult(ResultSet rs, String columnName) {
String code = rs.getString(columnName);
return OrderStatus.valueOf(code);
}
// 其他getNullableResult方法...
}3.2 基于編碼的轉(zhuǎn)換(推薦)
@MappedTypes(UserType.class)
public class UserTypeHandler extends BaseTypeHandler<UserType> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
UserType userType, JdbcType jdbcType) {
ps.setString(i, userType.getCode());
}
@Override
public UserType getNullableResult(ResultSet rs, String columnName) {
String code = rs.getString(columnName);
return UserType.fromCode(code);
}
}??注冊處理器??:
<typeHandlers>
<typeHandler handler="com.example.handler.UserTypeHandler"/>
</typeHandlers>??實(shí)體類使用??:
public class User {
@TableField(typeHandler = UserTypeHandler.class)
private UserType type;
}4. 枚舉值關(guān)聯(lián)表方案
CREATE TABLE user_types (
id TINYINT PRIMARY KEY AUTO_INCREMENT,
code CHAR(2) UNIQUE NOT NULL,
name VARCHAR(20) NOT NULL
);
INSERT INTO user_types (code, name) VALUES
('A', '管理員'),
('E', '編輯'),
('U', '普通用戶');??Mapper XML 查詢??:
<resultMap id="userResultMap" type="User">
<result property="id" column="id"/>
<association property="type" column="type_code"
select="selectUserTypeByCode"/>
</resultMap>
<select id="selectUserTypeByCode" resultType="UserType">
SELECT code, name AS description
FROM user_types
WHERE code = #[code]
</select>二、MyBatis-Plus 高級枚舉映射
1. 內(nèi)置枚舉處理器
public enum ProductStatus implements IEnum<Integer> {
DRAFT(0), PUBLISHED(1), ARCHIVED(2);
private final int value;
ProductStatus(int value) {
this.value = value;
}
@Override
public Integer getValue() {
return this.value;
}
}
// 實(shí)體類使用
public class Product {
private ProductStatus status;
}??全局配置(application.yml)??:
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler2. 字段注解映射
public class Product {
@TableField(value = "status",
typeHandler = ProductStatusHandler.class)
private ProductStatus status;
}3. JSON格式存儲枚舉屬性
public class Order {
@TableField(typeHandler = JsonTypeHandler.class)
private Map<OrderStatus, Integer> statusStatistics;
}??JSON存儲結(jié)構(gòu)??:
{
"NEW": 10,
"PAID": 5,
"DELIVERED": 3
}三、枚舉映射最佳實(shí)踐方案
1. 防御式枚舉設(shè)計(jì)
public enum OrderStatus {
NEW("N"), PAID("P"), DELIVERED("D"), CANCELLED("C");
private final String code;
private static final Map<String, OrderStatus> CODE_MAP = new HashMap<>();
static {
for (OrderStatus status : values()) {
CODE_MAP.put(status.code, status);
}
}
public static OrderStatus fromCode(String code) {
OrderStatus status = CODE_MAP.get(code);
if (status == null) {
if (code == null) return null;
String cleanCode = code.trim().toUpperCase();
return Optional.ofNullable(CODE_MAP.get(cleanCode))
.orElseThrow(() -> new IllegalArgumentException(
"無效狀態(tài)碼: " + code));
}
return status;
}
}2. 枚舉基類設(shè)計(jì)
public interface EnumCode {
String getCode();
String getDescription();
}
public abstract class BaseEnumHandler<E extends Enum<E> & EnumCode>
extends BaseTypeHandler<E> {
private final Class<E> type;
private final Map<String, E> enumMap;
public BaseEnumHandler(Class<E> type) {
this.type = type;
this.enumMap = Arrays.stream(type.getEnumConstants())
.collect(Collectors.toMap(EnumCode::getCode, e -> e));
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
E parameter, JdbcType jdbcType) {
ps.setString(i, parameter.getCode());
}
@Override
public E getNullableResult(ResultSet rs, String columnName) {
String code = rs.getString(columnName);
return code == null ? null : enumMap.get(code);
}
}四、實(shí)戰(zhàn)應(yīng)用場景
1. 多狀態(tài)組合(BIT存儲)
public enum Permission {
READ(1), WRITE(2), DELETE(4), EXECUTE(8);
private final int bitValue;
// 存儲所有權(quán)限值到單個整數(shù)
public static int encode(Set<Permission> permissions) {
return permissions.stream()
.mapToInt(p -> p.bitValue)
.sum();
}
public static Set<Permission> decode(int value) {
return Arrays.stream(values())
.filter(p -> (value & p.bitValue) != 0)
.collect(Collectors.toSet());
}
}
// MyBatis類型處理器
public class PermissionSetHandler extends BaseTypeHandler<Set<Permission>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Set<Permission> perms, JdbcType jdbcType) {
ps.setInt(i, Permission.encode(perms));
}
@Override
public Set<Permission> getNullableResult(ResultSet rs, String columnName) {
int value = rs.getInt(columnName);
return rs.wasNull() ? Collections.emptySet() : Permission.decode(value);
}
}2. 動態(tài)狀態(tài)機(jī)驗(yàn)證
public class OrderService {
@Transactional
public void updateOrderStatus(Long orderId, OrderStatus newStatus) {
Order order = orderMapper.selectById(orderId);
OrderStatus oldStatus = order.getStatus();
if (!oldStatus.isAllowedTransition(newStatus)) {
throw new IllegalStateException("狀態(tài)轉(zhuǎn)換非法: " +
oldStatus + " -> " + newStatus);
}
order.setStatus(newStatus);
orderMapper.updateById(order);
}
}
// 枚舉中定義狀態(tài)轉(zhuǎn)移規(guī)則
public enum OrderStatus {
NEW {
@Override
public boolean isAllowedTransition(OrderStatus newStatus) {
return newStatus == PAID || newStatus == CANCELLED;
}
},
// 其他狀態(tài)定義...
}五、性能優(yōu)化技巧
??靜態(tài)映射緩存??:
public abstract class CachedEnumHandler<E extends Enum<E> & EnumCode>
extends BaseTypeHandler<E> {
private final Map<String, E> codeEnumMap;
private final Map<E, String> enumCodeMap;
public CachedEnumHandler(Class<E> enumClass) {
E[] enums = enumClass.getEnumConstants();
codeEnumMap = Arrays.stream(enums)
.collect(Collectors.toMap(EnumCode::getCode, e -> e));
enumCodeMap = Arrays.stream(enums)
.collect(Collectors.toMap(e -> e, EnumCode::getCode));
}
}??批量處理優(yōu)化??:
@Mapper
public interface BatchMapper {
@Insert("<script>" +
"INSERT INTO users (type, name) VALUES " +
"<foreach item='item' collection='list' separator=','>" +
"(#{item.type, typeHandler=com.example.UserTypeHandler}, #{item.name})" +
"</foreach>" +
"</script>")
int batchInsertUsers(@Param("list") List<User> users);
}??數(shù)據(jù)庫約束優(yōu)化??:
-- MySQL ENUM 類型約束
status ENUM('NEW','PAID','DELIVERED','CANCELLED') NOT NULL DEFAULT 'NEW'
COMMENT '訂單狀態(tài)'
-- PostgreSQL檢查約束
ALTER TABLE orders
ADD CONSTRAINT status_check
CHECK (status IN ('NEW', 'PAID', 'DELIVERED', 'CANCELLED'));六、錯誤解決方案手冊
1. 序列化問題修復(fù)
// 添加枚舉序列化配置
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum OrderStatus implements EnumCode {
// ...
}
// 或自定義序列化器
public class EnumCodeSerializer extends StdSerializer<EnumCode> {
public EnumCodeSerializer() {
super(EnumCode.class);
}
@Override
public void serialize(EnumCode value, JsonGenerator gen,
SerializerProvider provider) {
gen.writeStartObject();
gen.writeStringField("code", value.getCode());
gen.writeStringField("description", value.getDescription());
gen.writeEndObject();
}
}2. 國際化方案
public interface LocalizedEnum {
String getCode();
default String getMessage(Locale locale) {
ResourceBundle bundle = ResourceBundle.getBundle(
"enum_messages", locale);
return bundle.getString(this.getClass().getSimpleName() + "." + getCode());
}
}
// 多語言資源文件
// en_US.properties
UserType.A=Administrator
UserType.E=Editor
UserType.U=User
// zh_CN.properties
UserType.A=管理員
UserType.E=編輯
UserType.U=普通用戶總結(jié):MyBatis枚舉映射決策樹
graph TD
A[需要映射枚舉] --> B{是否簡單狀態(tài)值?}
B --> |是| C{是否確定永不修改順序?}
C --> |是| D[使用EnumTypeHandler默認(rèn)序數(shù)映射]
C --> |否| E[使用EnumOrdinalTypeHandler名稱映射]
B --> |否| F{是否需要業(yè)務(wù)編碼?}
F --> |是| G[自定義TypeHandler+編碼設(shè)計(jì)]
F --> |否| H{是否多語言/復(fù)雜屬性?}
H --> |是| I[關(guān)聯(lián)表映射方案]
H --> |否| J[直接使用MyBatis-Plus枚舉方案]??企業(yè)級應(yīng)用建議??:
- 選擇??自定義編碼映射??作為默認(rèn)方案
- 對性能敏感的常量枚舉使用??序數(shù)映射??
- 需要多語言支持的使用??關(guān)聯(lián)表映射??
- 組合狀態(tài)使用??BIT存儲+解碼方案??
遵循這些模式,可構(gòu)建出健壯且易維護(hù)的枚舉持久化層,完美平衡數(shù)據(jù)庫高效存儲與業(yè)務(wù)代碼的可讀性需求。
到此這篇關(guān)于MyBatis 枚舉映射的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)MyBatis 枚舉映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA集成DeepSeek的詳細(xì)教程(保姆級教程)
DeepSeek作為一款強(qiáng)大的代碼搜索和分析工具,能夠幫助開發(fā)者快速定位代碼、理解項(xiàng)目結(jié)構(gòu)以及優(yōu)化代碼質(zhì)量,本文將詳細(xì)介紹如何在IntelliJ?IDEA中集成DeepSeek,并展示如何利用它來提升開發(fā)效率,感興趣的朋友一起看看吧2025-02-02
Java實(shí)現(xiàn)的簡單數(shù)字時鐘功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的簡單數(shù)字時鐘功能,涉及java日期時間及JFrame框架圖形界面操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-02-02
springboot如何接收復(fù)雜參數(shù)(同時接收J(rèn)SON與文件)
文章介紹了在Spring Boot中同時處理JSON和文件上傳時使用`@RequestPart`注解的方法,`@RequestPart`可以接收多種格式的參數(shù),包括JSON和文件,并且可以作為`multipart/form-data`格式中的key2025-02-02
MyBatis使用自定義TypeHandler轉(zhuǎn)換類型的實(shí)現(xiàn)方法
這篇文章主要介紹了MyBatis使用自定義TypeHandler轉(zhuǎn)換類型的實(shí)現(xiàn)方法,本文介紹使用TypeHandler 實(shí)現(xiàn)日期類型的轉(zhuǎn)換,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-10-10
java 配置MyEclipse Maven環(huán)境具體實(shí)現(xiàn)步驟
這篇文章主要介紹了 java 配置MyEclipse Maven環(huán)境具體實(shí)現(xiàn)步驟的相關(guān)資料,具有一定的參考價值,需要的朋友可以參考下2016-11-11
Java?KeyGenerator.generateKey的19個方法代碼示例
在下文中一共展示了KeyGenerator.generateKey方法的19個代碼示例,這些例子默認(rèn)根據(jù)受歡迎程度排序2021-12-12

