枚舉類雖然很簡單,但是卻往往是系統中業務邏輯最集中最複雜的地方。本文將會分享我們項目中基於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