1. 程式人生 > >使用註解風格學習Hibernate和JPA的主鍵生成策略

使用註解風格學習Hibernate和JPA的主鍵生成策略

               

      主鍵是關係資料庫中的一個基本概念,它用來保證記錄的唯一性。簡單來說,就是同一張資料庫表中,不允許存在多條相同主鍵的記錄。主鍵生成策略,就是當向資料庫表中插入記錄的時候,這個記錄的主鍵該如何生成。絕大部分情況下,主鍵都是沒有業務含義的,所以開發者不會、也不需要,顯示地設定實體物件的主鍵值。但是對於資料庫來說,主鍵是必須的,顯然這個責任,落在了hibernate這個持久層框架上。對於初學hibernate的人來說,往往會被一堆的主鍵生成策略弄暈,本文介紹下一些容易混淆的概念,希望能幫助大家瞭解hibernate主鍵生成策略。

       Hibernate內建了很多主鍵生成策略,這些策略可以分為兩類:一類是JPA標準的主鍵生成策略,一類是Hibernate框架特有的主鍵生成策略。JPA標準策略有4種:auto策略、table策略、sequence策略、identity策略;餘下的都是hibernate自己的策略,包括我們常用的native、uuid、assigned、sequence等。

1.JPA和Hibernate的區別

       JPA全稱Java Persistence API,是sun公司針對ORM技術提出的技術規範,用來將POJO按照標準的方式進行持久化,很類似於JDBC規範。Hibernate最早是以ORM框架形式出現的,用來解決JDBC存在的問題。隨著JPA標準的發展和完善,hibernate到後來也開始支援JPA規範,並且能夠完全相容JPA規範。也就說,hibernate是JPA標準的一個實現,還在此基礎上增加了一些自己特有的功能。這就是我們常說的:JPA是hibernate的一個子集,hibernate是JPA的超集。

2.JPA的4種策略介紹

  • AUTO策略

 auto策略是JPA預設的策略,在hibernate的程式碼 GenerationType.AUTO 

進行定義。使用 AUTO 策略就是將主鍵生成的策略交給持久化引擎 (persistence   engine) 來決定,由它自己從 Table 策略,Sequence 策略和 Identity策略三種策略中選擇最合適的。不同的持久化引擎 、不同的資料庫一般策略不同。比如oracle最常用的就 是sequence,mysql最常用的就是identify,因為oracle資料庫支援sequence,而mysql資料庫則 是隻支援 auto_increment 。

  • Sequence策略

對應Hibernate程式碼 GenerationType.SEQUENCE 。一些資料庫,如oracle就會內建"序列生成器"。為了使用序列,我們需要使用JPA的sequence策略。

  • Identity策略

對應Hibernate程式碼 GenerationType.IDENTITY 。 這個很適合像mysql這樣的資料庫,提供了對自增主鍵的支援。

  • Table策略

對應Hibernate程式碼 GenerationType.TABLE 。 使用一張特殊的資料庫表,儲存插入記錄的時,需要的主鍵值。

3.註解風格使用JPA主鍵生成策略

   配置實體主鍵生成策略的時候,需要用到@GeneratedValue主鍵
  • 使用AUTO策略

對應的java程式碼如下:

public classTeacher{private int id;private String title;@Id@GeneratedValue(strategy = GenerationType.AUTO)publicint getId(){return id;}}
我使用的是mysql對應的資料庫表如下:注意:

1、如果是mysql資料庫,一定要將主鍵列設定成自增長的,否則使用AUTO策略的時候,會報錯:

org.hibernate.exception.GenericJDBCException: Field 'id' doesn't have a default value 

2、如果是oracle資料庫,那麼會使用hibernate_sequence,這個名稱是固定的,不能更改。

  • 使用sequence策略
public classTeacher{private int id;private String title;@Id@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="mySeqGenerator")@SequenceGenerator(name = "mySeqGenerator", sequenceName = "t_teacher_sequence", initialValue = 1000, allocationSize = 50)publicint getId(){return id;}}
這裡需要配合使用@SequenceGenerator,用來指定序列的相關資訊。

name:序列生成器的名稱,會在@GeneratedValue中進行引用

sequenceName:oracle資料庫中的序列生成器名稱

initialValue:主鍵的初始值

allocationSize:主鍵每次增長值的大小 

注意:如果底層資料庫不執行序列,會報錯:

org.hibernate.MappingException: org.hibernate.dialect.MySQLDialect does not support sequences

  • 使用Identity策略
public classTeacher{private int id;private String title;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)publicint getId(){return id;}}
使用比較簡單,這裡不需要做詳細介紹了
  • 使用Table策略
public classTeacher{private int id;private String title;@Id@GeneratedValue(strategy = GenerationType.TABLE,generator="myTableGenerator")@TableGenerator(name = "myTableGenerator", table = "hibernateNeedTable", pkColumnName = "pk_key", valueColumnName = "pk_value", pkColumnValue = "teacherId", initialValue = 100, allocationSize = 1000)publicint getId(){return id;}}
不知道怎麼用合適的語言來描述這些屬性的含義。直接上圖和執行的sql語句,讀者只需要簡單理解下,就能明白這些屬性的含義了。

1、我們資料庫中多了一張表

2、實際發出的sql語句如下:

Hibernate: selectpk_value fromhibernateNeedTable wherepk_key = 'teacherId' for updateHibernate: updatehibernateNeedTable setpk_value = ? wherepk_value = ? and pk_key = 'teacherId'Hibernate: insert intoTeacher(title, id) values(?, ?)
看到這裡,大家應該明白了這些屬性的用法了。值得一提的是,這個表可以給無數的表作為主鍵表,只是新增一條記錄而以(需要保證table、pkColumnName、valueColumnName三個屬性值唯一就可以了。