1. 程式人生 > >JPA之@GeneratedValue註解和連線例項

JPA之@GeneratedValue註解和連線例項

本文雖然是小熙轉載,但在此基礎上也加了些小熙個人的連線例項、見解、博文連結,希望大家喜歡

JPA的@GeneratedValue註解,在JPA中,@GeneratedValue註解存在的意義主要就是為一個實體生成一個唯一標識的主鍵(JPA要求每一個實體Entity,必須有且只有一個主鍵),@GeneratedValue提供了主鍵的生成策略。@GeneratedValue註解有兩個屬性,分別是strategy和generator,其中generator屬性的值是一個字串,預設為"",其聲明瞭主鍵生成器的名稱(對應於同名的主鍵生成器@SequenceGenerator和@TableGenerator)。

JPA為開發人員提供了四種主鍵生成策略,其被定義在列舉類GenerationType中,包括GenerationType.TABLE,GenerationType.SEQUENCE,GenerationType.IDENTITY和GenerationType.AUTO。下面分別介紹這四種主鍵生成策略。

1. GenerationType.TABLE

使用一個特定的資料庫表格來儲存主鍵,持久化引擎通過關係資料庫的一張特定的表格來生成主鍵,這種策略的好處就是不依賴於外部環境和資料庫的具體實現,在不同資料庫間可以很容易的進行移植,但由於其不能充分利用資料庫的特性,所以不會優先使用。該策略一般與另外一個註解一起使用@TableGenerator,@TableGenerator註解指定了生成主鍵的表(可以在實體類上指定也可以在主鍵欄位或屬性上指定),然後JPA將會根據註解內容自動生成一張表作為序列表(或使用現有的序列表)。如果不指定序列表,則會生成一張預設的序列表,表中的列名也是自動生成,資料庫上會生成一張名為sequence的表(SEQ_NAME,SEQ_COUNT)。序列表一般只包含兩個欄位:第一個欄位是該生成策略的名稱,第二個欄位是該關係表的最大序號,它會隨著資料的插入逐漸累加。類似於

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "roleSeq")
    @TableGenerator(name = "roleSeq", allocationSize = 1, table = "seq_table", pkColumnName = "seq_id", valueColumnName = "seq_count")
    private Integer id;

在以上例子中,roleSeq唯一的標識了該生成器,在@GeneratedValue註解中的generator屬性可以根據此標識來宣告主鍵生成器。

2. GenerationType.SEQUENCE(常用於hibernate連線Oracle)

(1) 在某些資料庫中,不支援主鍵自增長,比如Oracle,其提供了一種叫做"序列(sequence)"的機制生成主鍵。此時,GenerationType.SEQUENCE就可以作為主鍵生成策略。該策略的不足之處正好與TABLE相反,由於只有部分資料庫(Oracle,PostgreSQL,DB2)支援序列物件,所以該策略一般不應用於其他資料庫。類似的,該策略一般與另外一個註解一起使用@SequenceGenerator,@SequenceGenerator註解指定了生成主鍵的序列.然後JPA會根據註解內容建立一個序列(或使用一個現有的序列)。如果不指定序列,則會自動生成一個序列SEQ_GEN_SEQUENCE。類似於

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "menuSeq")
    @SequenceGenerator(name = "menuSeq", initialValue = 1, allocationSize = 1, sequenceName = "MENU_SEQUENCE")
    private Integer id;

同樣,在以上例子中,menuSeq唯一的標識了該生成器,@SequenceGenerator可以理解為將資料庫中存在的序列進行了一個對映,在@GeneratedValue註解中的generator屬性可以根據此標識來宣告主鍵生成器。

(2) 其實也可以由Oracle建立序列,設定觸發器。讓mybatis連線Oracle實現同連線mysql主鍵自增長相同的效果。

  1. Oracle設定觸發器實現主鍵自增長的詳細描述請看,小熙的另一篇部落格:Oracle資料庫設定主鍵自增長(案例的實體類也是採用這篇部落格的)

  2. 之後需要在主鍵處設定預設值,測試時不寫id值會不能通過Oracle檢查的,因為輸入值不能為null,為了方便小熙就在pojo類中的主鍵處設定了預設值。

   @Id
   private Integer id = 1;
  1. 之後就是測試添加了
    @Test
    public void addOracleData(){
        UserTest userTest = new UserTest();
        userTest.setName("程熙");
        userTest.setSex("男");

        userTestMapper.insert(userTest);
    }
  1. 如圖就新增成功了,主鍵也是向Oracle插入資料時,觸發器呼叫序列生成的
    主鍵自增

3. GenerationType.IDENTITY(常用於mybatis連線mysql)

此種主鍵生成策略就是通常所說的主鍵自增長,資料庫在插入資料時,會自動給主鍵賦值,比如MYSQL可以在建立表時宣告"auto_increment" 來指定主鍵自增長。該策略在大部分資料庫中都提供了支援(指定方法或關鍵字可能不同),但還是有少數資料庫不支援,所以可移植性略差。使用自增長主鍵生成策略是隻需要宣告strategy = GenerationType.IDENTITY即可。類似於

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

需要注意的是,同一張表中自增列最多隻能有一列。

4. GenerationType.AUTO

把主鍵生成策略交給持久化引擎(persistence engine),持久化引擎會根據資料庫在以上三種主鍵生成策略中選擇其中一種。此種主鍵生成策略比較常用,由於JPA預設的生成策略就是GenerationType.AUTO,所以使用此種策略時.可以顯式的指定@GeneratedValue(strategy = GenerationType.AUTO)也可以直接@GeneratedValue

類似於

    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @GeneratedValue
    private Integer id;

5. 如果主鍵為String有此建議

Oracle中的SYS_GUID()函式,在Oracle 8i以後提供sys_guid ()方法,系統根據當前時間和機器碼,生成全球唯一的一個序列號。
方法使用場景:
這在物件在不同機器的不同資料庫裡生成以及需要在後來合併到一起的情況下很有用,因為這樣可以防止主鍵衝突。
因為採用sequence的話,只能保證在同一個資料中該序列號唯一,但是在不同的資料庫例項中有可能衝突。

該方法的弊端:
由於sys_guid ()生成的序列號過長,這會消耗資料庫儲存空間,且管理不方便。
基於此,在非並行環境下的資料庫應用中,應儘量避免使用sys_guid ()

效果如圖:

SELECT sys_guid() FROM dual;
sys

參考資料:
JPA主鍵生成器和主鍵生成策略
JPA批註參考

測試例項:
JPA註解@Access例項