使用註解風格學習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
- 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三個屬性值唯一就可以了。