Hibernate框架主鍵生成策略

之前在用Hibernate框架寫東西的時(shí)候,經(jīng)常會(huì)去寫映射文件hbm.xml。但是對(duì)于主鍵id的一個(gè)generate屬性了解的不是特別多。經(jīng)過查閱資料學(xué)習(xí),這次來好好地總結(jié)一下。

主鍵生成策略

** 所有主鍵生成策略: **

  1. identity

  2. sequence

  3. hilo

  4. native

  5. uuid

  6. assigned

  7. increment

  8. seqhilo

  9. guid

  10. foreign

  11. select

** 其中前六個(gè)是經(jīng)常用到的 **

** 接下來分別總結(jié)一個(gè)各個(gè)主鍵生成策略的具體內(nèi)容 **

  • identity

identity由底層數(shù)據(jù)庫生成標(biāo)識(shí)符。identity是由數(shù)據(jù)庫自己生成的,但這個(gè)主鍵必須設(shè)置為自增長,使用identity的前提條件是底層數(shù)據(jù)庫支持自動(dòng)增長字段類型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle這類沒有自增字段的則不支持。

<id name="id" column="id">

<generator class="identity" />

</id>

例:如果使用MySQL數(shù)據(jù)庫,則主鍵字段必須設(shè)置成auto_increment。

id int(11) primary key auto_increment

特點(diǎn):只能用在支持自動(dòng)增長的字段數(shù)據(jù)庫中使用,如MySQL。

  • sequence

采用數(shù)據(jù)庫提供的sequence機(jī)制生成主鍵,需要數(shù)據(jù)庫支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL這種不支持sequence的數(shù)據(jù)庫則不行(可以使用identity)。

<generator class="sequence">

<param name="sequence">hibernate_id</param>

</generator>

<!--指定sequence的名稱-->
<param name="sequence">hibernate_id</param> 

Hibernate生成主鍵時(shí),查找sequence并賦給主鍵值,主鍵值由數(shù)據(jù)庫生成,Hibernate不負(fù)責(zé)維護(hù),使用時(shí)必須先創(chuàng)建一個(gè)sequence,如果不指定sequence名稱,則使用Hibernate默認(rèn)的sequence,名稱為hibernate_sequence,前提要在數(shù)據(jù)庫中創(chuàng)建該sequence。

特點(diǎn):只能在支持序列的數(shù)據(jù)庫中使用,如Oracle。

  • hilo

hilo(高低位方式high low)是hibernate中最常用的一種生成方式,需要一張額外的表保存hi的值。保存hi值的表至少有一條記錄(只與第一條記錄有關(guān)),否則會(huì)出現(xiàn)錯(cuò)誤??梢钥鐢?shù)據(jù)庫。

<id name="id" column="id">

<generator class="hilo">

<param name="table">hibernate_hilo</param>

<param name="column">next_hi</param>

<param name="max_lo">100</param>

</generator>

</id>

其中

<param name="table">hibernate_hilo</param> <!--指定保存hi值的表名-->

<param name="column">next_hi</param> <!--指定保存hi值的列名-->

<param name="max_lo">100</param> <!--指定低位的最大值-->

<!--也可以省略table和column配置,其默認(rèn)的表為hibernate_unique_key,列為next_hi-->

<id name="id" column="id">

<generator class="hilo">

<param name="max_lo">100</param>

</generator>

</id>

hilo生成器生成主鍵的過程(以hibernate_unique_key表,next_hi列為例):

  1. 獲得hi值:讀取并記錄數(shù)據(jù)庫的hibernate_unique_key表中next_hi字段的值,數(shù)據(jù)庫中此字段值加1保存。

  2. 獲得lo值:從0到max_lo循環(huán)取值,差值為1,當(dāng)值為max_lo值時(shí),重新獲取hi值,然后lo值繼續(xù)從0到max_lo循環(huán)。

  3. 根據(jù)公式 hi * (max_lo + 1) + lo計(jì)算生成主鍵值。

注意:當(dāng)hi值是0的時(shí)候,那么第一個(gè)值不是0*(max_lo+1)+0=0,而是lo跳過0從1開始,直接是1、2、3……

那max_lo配置多大合適呢?

這要根據(jù)具體情況而定,如果系統(tǒng)一般不重啟,而且需要用此表建立大量的主鍵,可以吧max_lo配置大一點(diǎn),這樣可以減少讀取數(shù)據(jù)表的次數(shù),提高效率;反之,如果服務(wù)器經(jīng)常重啟,可以吧max_lo配置小一點(diǎn),可以避免每次重啟主鍵之間的間隔太大,造成主鍵值主鍵不連貫。

特點(diǎn):跨數(shù)據(jù)庫,hilo算法生成的標(biāo)志只能在一個(gè)數(shù)據(jù)庫中保證唯一。

  • native

native由hibernate根據(jù)使用的數(shù)據(jù)庫自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式,靈活性很強(qiáng)。如果能支持identity則使用identity,如果支持sequence則使用sequence。

<id name="id" column="id">

<generator class="native" />

</id>

例如MySQL使用identity,Oracle使用sequence

注意:如果Hibernate自動(dòng)選擇sequence或者h(yuǎn)ilo,則所有的表的主鍵都會(huì)從Hibernate默認(rèn)的sequence或hilo表中取。并且,有的數(shù)據(jù)庫對(duì)于默認(rèn)情況主鍵生成測試的支持,效率并不是很高。

使用sequence或hilo時(shí),可以加入?yún)?shù),指定sequence名稱或hi值表名稱等,如

<param name="sequence">hibernate_id</param>

特點(diǎn):根據(jù)數(shù)據(jù)庫自動(dòng)選擇,項(xiàng)目中如果用到多個(gè)數(shù)據(jù)庫時(shí),可以使用這種方式,使用時(shí)需要設(shè)置表的自增字段或建立序列,建立表等。

  • uuid

UUID:Universally Unique Identifier,是指在一臺(tái)機(jī)器上生成的數(shù)字,它保證對(duì)在同一時(shí)空中的所有機(jī)器都是唯一的。按照開放軟件基金會(huì)(OSF)制定的標(biāo)準(zhǔn)計(jì)算,用到了以太網(wǎng)卡地址、納秒級(jí)時(shí)間、芯片ID碼和許多可能的數(shù)字,標(biāo)準(zhǔn)的UUID格式為:

xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)

其中每個(gè) x 是 0-9 或 a-f 范圍內(nèi)的一個(gè)十六進(jìn)制的數(shù)字。

<id name="id" column="id">

<generator class="uuid" />

</id>

Hibernate在保存對(duì)象時(shí),生成一個(gè)UUID字符串作為主鍵,保證了唯一性,但其并無任何業(yè)務(wù)邏輯意義,只能作為主鍵,唯一缺點(diǎn)長度較大,32位(Hibernate將UUID中間的“-”刪除了)的字符串,占用存儲(chǔ)空間大,但是有兩個(gè)很重要的優(yōu)點(diǎn),Hibernate在維護(hù)主鍵時(shí),不用去數(shù)據(jù)庫查詢,從而提高效率,而且它是跨數(shù)據(jù)庫的,以后切換數(shù)據(jù)庫極其方便。

特點(diǎn):uuid長度大,占用空間大,跨數(shù)據(jù)庫,不用訪問數(shù)據(jù)庫就生成主鍵值,所以效率高且能保證唯一性,移植非常方便,推薦使用。

  • assigned

主鍵由外部程序負(fù)責(zé)生成,在 save() 之前必須指定一個(gè)。Hibernate不負(fù)責(zé)維護(hù)主鍵生成。與Hibernate和底層數(shù)據(jù)庫都無關(guān),可以跨數(shù)據(jù)庫。在存儲(chǔ)對(duì)象前,必須要使用主鍵的setter方法給主鍵賦值,至于這個(gè)值怎么生成,完全由自己決定,這種方法應(yīng)該盡量避免。

<id name="id" column="id">

<generator class="assigned" />

</id>

“ud”是自定義的策略名,人為起的名字,后面均用“ud”表示。

特點(diǎn):可以跨數(shù)據(jù)庫,人為控制主鍵生成,應(yīng)盡量避免。

  • increment

由Hibernate從數(shù)據(jù)庫中取出主鍵的最大值(每個(gè)session只取1次),以該值為基礎(chǔ),每次增量為1,在內(nèi)存中生成主鍵,不依賴于底層的數(shù)據(jù)庫,因此可以跨數(shù)據(jù)庫。

<id name="id" column="id">

<generator class="increment" />

</id>

Hibernate調(diào)用org.hibernate.id.IncrementGenerator類里面的generate()方法,使用select max(idColumnName) from tableName語句獲取主鍵最大值。該方法被聲明成了synchronized,所以在一個(gè)獨(dú)立的Java虛擬機(jī)內(nèi)部是沒有問題的,然而,在多個(gè)JVM同時(shí)并發(fā)訪問數(shù)據(jù)庫select max時(shí)就可能取出相同的值,再insert就會(huì)發(fā)生Dumplicate entry的錯(cuò)誤。所以只能有一個(gè)Hibernate應(yīng)用進(jìn)程訪問數(shù)據(jù)庫,否則就可能產(chǎn)生主鍵沖突,所以不適合多進(jìn)程并發(fā)更新數(shù)據(jù)庫,適合單一進(jìn)程訪問數(shù)據(jù)庫,不能用于群集環(huán)境。

官方文檔:只有在沒有其他進(jìn)程往同一張表中插入數(shù)據(jù)時(shí)才能使用,在集群下不要使用。

特點(diǎn):跨數(shù)據(jù)庫,不適合多進(jìn)程并發(fā)更新數(shù)據(jù)庫,適合單一進(jìn)程訪問數(shù)據(jù)庫,不能用于群集環(huán)境。

  • seqhilo

與hilo類似,通過hi/lo算法實(shí)現(xiàn)的主鍵生成機(jī)制,只是將hilo中的數(shù)據(jù)表換成了序列sequence,需要數(shù)據(jù)庫中先創(chuàng)建sequence,適用于支持sequence的數(shù)據(jù)庫,如Oracle。

<id name="id" column="id">

<generator class="seqhilo">

<param name="sequence">hibernate_seq</param>

<param name="max_lo">100</param>

</generator>

</id>

特點(diǎn):與hilo類似,只能在支持序列的數(shù)據(jù)庫中使用。

  • guid

GUID:Globally Unique Identifier全球唯一標(biāo)識(shí)符,也稱作 UUID,是一個(gè)128位長的數(shù)字,用16進(jìn)制表示。算法的核心思想是結(jié)合機(jī)器的網(wǎng)卡、當(dāng)?shù)貢r(shí)間、一個(gè)隨即數(shù)來生成GUID。從理論上講,如果一臺(tái)機(jī)器每秒產(chǎn)生10000000個(gè)GUID,則可以保證(概率意義上)3240年不重復(fù)。

<id name="id" column="id">

<generator class="guid" />

</id>

Hibernate在維護(hù)主鍵時(shí),先查詢數(shù)據(jù)庫,獲得一個(gè)uuid字符串,該字符串就是主鍵值,該值唯一,缺點(diǎn)長度較大,支持?jǐn)?shù)據(jù)庫有限,優(yōu)點(diǎn)同uuid,跨數(shù)據(jù)庫,但是仍然需要訪問數(shù)據(jù)庫。

注意:長度因數(shù)據(jù)庫不同而不同

MySQL中使用select uuid()語句獲得的為36位(包含標(biāo)準(zhǔn)格式的“-”)

Oracle中,使用select rawtohex(sys_guid()) from dual語句獲得的為32位(不包含“-”)

特點(diǎn):需要數(shù)據(jù)庫支持查詢uuid,生成時(shí)需要查詢數(shù)據(jù)庫,效率沒有uuid高,推薦使用uuid。

  • foreign

使用另外一個(gè)相關(guān)聯(lián)的對(duì)象的主鍵作為該對(duì)象主鍵。主要用于一對(duì)一關(guān)系中。

<id name="id" column="id">

<generator class="foreign">

<param name="property">user</param>

</generator>

</id>

<one-to-one name="user" class="domain.User" constrained="true" />

該例使用domain.User的主鍵作為本類映射的主鍵。

特點(diǎn):很少使用,大多用在一對(duì)一關(guān)系中。

  • select

使用觸發(fā)器生成主鍵,主要用于早期的數(shù)據(jù)庫主鍵生成機(jī)制,能用到的地方非常少。

參考資料: Fra~~kaka's Blog

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • class 可配置項(xiàng) native:根據(jù)使用的數(shù)據(jù)庫幫你選擇哪個(gè)值 uuid:類似C#Guid 1、assigne...
    垃圾簡書_吃棗藥丸閱讀 564評(píng)論 0 2
  • Hibernate是一個(gè)開放源代碼的對(duì)象關(guān)系映射框架,它對(duì)JDBC進(jìn)行了非常輕量級(jí)的對(duì)象封裝,它將POJO與數(shù)據(jù)庫...
    蘭緣小妖閱讀 1,273評(píng)論 1 18
  • 1.主鍵生成策略 1.1 主鍵的兩種類型 自然主鍵:把數(shù)據(jù)表中的某一業(yè)務(wù)字段作為表的主鍵。如一張用戶表中,把用戶的...
    Wizey閱讀 587評(píng)論 0 3
  • 第一節(jié)手繪課,收獲滿滿噠! 跟著心藍(lán)老師一起學(xué)習(xí),Get到四種畫線稿的常用方法啦! A.概括分析法 B.比例測量法...
    黑米小鋪閱讀 355評(píng)論 1 1

友情鏈接更多精彩內(nèi)容