hibernate 使用枚舉字段的最佳實踐


枚舉類雖然很簡單,但是卻往往是系統中業務邏輯最集中最復雜的地方。本文將會分享我們項目中基於hibernate的枚舉類使用規范,包含數據庫中枚舉列數據類型、注釋、枚舉列與枚舉類的映射等。

 

一、枚舉類定義規范

 

 1 package org.jframe.data.enums;
 2 
 3 /**
 4  * Created by leo on 2017-05-31.
 5  */
 6 public enum Gender {
 7     unknown(0),
 8     male(11),
 9     female(12);
10 
11     public final static String Doc = "0: unknown; 11: male; 12: female";
12 
13     private final int value;
14     private Gender(int value){
15         this.value = value;
16     }
17 
18     public int getValue(){
19         return this.value;
20     }
21 
22 }

 

請注意,枚舉類一定要包含一個常量字符串用於說明每一個枚舉值的作用。為什么一定要放在枚舉類里面?那是因為每當枚舉值有改變的的時候,能夠不用想都知道修改這個說明文檔。這個說明文檔在哪些地方用到呢?1: 數據庫定義(見下文);2:swagger API自動文檔。

 

二、數據庫定義

@Column(name = "gender", columnDefinition = "int not null COMMENT '" + Gender.Doc + "'")
@Convert(converter = GenderConverter.class)
private Gender gender;

 

上一步定義的枚舉類說明,在這里的columnDefinition就用到了。這樣,如果使用code first模式生成數據庫,那么數據庫中該列就會包含該枚舉類的說明文檔了。這也是我們強烈建議使用code first模式的重要原因。

 

最大的好處:使用強類型的枚舉類而不是string或int類型。

 

關於數據庫定義,有幾個為什么需要解釋一下。

 

1. 為什么使用int類型而非@Enumerated(EnumType.STRING)?答:java代碼中的枚舉類的成員隨時可能會改變,比如之前拼寫錯誤需要重構,或者就是任何理由的重構,雖然代碼改了,但是數據庫中已經存在的記錄還是使用原來的枚舉值,這就非常危險了。所以,使用EnumType.STRING是極其危險的,因為你改了代碼而沒有任何地方通知你去改老數據,這對於新手程序員來講就很容易寫出危險的代碼了,這就不是一個好的架構師該做的架構了。

 

2. 為什么一定要是使用AttributeConverter?答:如果不使用這個converter,hibernate默認會根據java代碼中枚舉成員出現的順序的index作為存到數據庫中的值。這就極其危險了。因為我們很有可能重構代碼調整枚舉成員順序,或者插入新的成員,但是數據庫中已經存在的記錄還是原來的順序值。所以,不使用attributeconverter是極其危險的,因為你改了代碼而沒有任何地方通知你去改老數據,這對於新手程序員來講就很容易寫出危險的代碼了,這就不是一個好的架構師該做的架構了。

 

三、AttributeConverter

 1 package org.jframe.data.converters;
 2 
 3 import org.jframe.data.enums.Gender;
 4 import org.jframe.infrastructure.core.JList;
 5 
 6 import javax.persistence.AttributeConverter;
 7 
 8 /**
 9  * Created by leo on 2017-06-28.
10  */
11 public class GenderConverter implements AttributeConverter<Gender, Integer> {
12     @Override
13     public Integer convertToDatabaseColumn(Gender gender) {
14         return gender.getValue();
15     }
16 
17     @Override
18     public Gender convertToEntityAttribute(Integer integer) {
19         return JList.from(Gender.values()).firstOrNull(x -> x.getValue() == integer);
20     }
21 }

 

這就很簡單了,無需贅述。

 

四、心得

相比於.NET體系下面的entity framework,可以看到hibernate的架構師給程序員挖了兩個坑。使用entity framework,即便是初級程序員也很難因為改了枚舉類代碼導致數據庫的數據錯誤,但是使用hibernate就不一樣了,即便是很多中高級程序員,也很容易因為改了枚舉類代碼而導致數據庫中的數據錯誤。

 

所以,我們項目中就建立了上面所描述的規范,如果沒有這個規范,程序員就很容易因為改了代碼而忘記改數據庫導致嚴重數據錯誤。

 

本文中的代碼來自jframe 框架

基於spring mvc搭建的多層級多模塊java web應用程序框架。包含:基礎設施層、數據庫定義規范、數據庫訪問規范、日志記錄規范、多層級異常捕獲、標准ajax規范、母版頁規范、視圖呈現規范、JavaScript框架規范等。實際上該框架定義的規范極其詳細,比如數據庫定義層:枚舉類使用規范、datetime/bool/string字段規范、1對1、1對多、多對1、多對多外鍵關系映射規范、父類定義規范、字段注釋規范、懶加載規范等等。。。

 

jframe github地址: https://github.com/leotsai/jframe,技術交流QQ群:651499479,歡迎java大神加群,也歡迎新手進群學習。

 

如果你們項目中有更好的枚舉類使用經驗,請一定要分享出來哦!

 

THE END


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM