Hibernate-05-主鍵生成策略

主鍵生成策略

class 可配置項(xiàng)

  1. native:根據(jù)使用的數(shù)據(jù)庫幫你選擇哪個(gè)值
  2. uuid:類似C#Guid

1欺旧、assigned
主鍵由外部程序負(fù)責(zé)生成绍移,在 save() 之前必須指定一個(gè)饵蒂。Hibernate不負(fù)責(zé)維護(hù)主鍵生成蓄喇。與Hibernate和底層數(shù)據(jù)庫都無關(guān)骗污,可以跨數(shù)據(jù)庫肌括。在存儲(chǔ)對象前,必須要使用主鍵的setter方法給主鍵賦值泛范,至于這個(gè)值怎么生成让虐,完全由自己決定,這種方法應(yīng)該盡量避免罢荡。

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

<generator class="assigned" />

</id>

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

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

2晕城、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)境襟沮。

3、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ù)庫中保證唯一酵熙。

4、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ù)庫中使用分飞。
5、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>

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

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蒸其。

6敏释、identity
identity由底層數(shù)據(jù)庫生成標(biāo)識符。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。

7沐悦、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ù)庫對于默認(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è)置表的自增字段或建立序列督笆,建立表等芦昔。

8、uuid
UUID:Universally Unique Identifier娃肿,是指在一臺(tái)機(jī)器上生成的數(shù)字咕缎,它保證對在同一時(shí)空中的所有機(jī)器都是唯一的。按照開放軟件基金會(huì)(OSF)制定的標(biāo)準(zhǔn)計(jì)算料扰,用到了以太網(wǎng)卡地址凭豪、納秒級時(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在保存對象時(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ù)庫就生成主鍵值氮块,所以效率高且能保證唯一性绍载,移植非常方便,推薦使用滔蝉。

9击儡、guid
GUID:Globally Unique Identifier全球唯一標(biāo)識符,也稱作 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送悔。

10慢显、foreign
使用另外一個(gè)相關(guān)聯(lián)的對象的主鍵作為該對象主鍵。主要用于一對一關(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):很少使用,大多用在一對一關(guān)系中洁段。

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

12除嘹、其他注釋方式配置
注釋方式與配置文件底層實(shí)現(xiàn)方式相同,只是配置的方式換成了注釋方式

自動(dòng)增長岸蜗,適用于支持自增字段的數(shù)據(jù)庫

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

根據(jù)底層數(shù)據(jù)庫自動(dòng)選擇方式憾赁,需要底層數(shù)據(jù)庫的設(shè)置

如MySQL,會(huì)使用自增字段散吵,需要將主鍵設(shè)置成auto_increment龙考。

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

使用表存儲(chǔ)生成的主鍵,可以跨數(shù)據(jù)庫矾睦。

每次需要主鍵值時(shí)晦款,查詢名為"hibernate_table"的表,查找主鍵列"gen_pk"值為"2"記錄枚冗,得到這條記錄的"gen_val"值缓溅,根據(jù)這個(gè)值,和allocationSize的值生成主鍵值赁温。

@Id

@GeneratedValue(strategy = GenerationType.TABLE, generator = "ud")

@TableGenerator(name = "ud",

table = "hibernate_table",

pkColumnName = "gen_pk",

pkColumnValue = "2",

valueColumnName = "gen_val",

initialValue = 2,

allocationSize = 5)

使用序列存儲(chǔ)主鍵值

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ud")

@SequenceGenerator(name = "ud",

sequenceName = "hibernate_seq",

allocationSize = 1,

initialValue = 2)

13坛怪、小結(jié)
1、為了保證對象標(biāo)識符的唯一性與不可變性股囊,應(yīng)該讓Hibernate來為主鍵賦值袜匿,而不是程序。

2稚疹、正常使用Hibernate維護(hù)主鍵居灯,最好將主鍵的setter方法設(shè)置成private,從而避免人為或程序修改主鍵内狗,而使用assigned方式怪嫌,就不能用private,否則無法給主鍵賦值柳沙。

2岩灭、Hibernate中唯一一種最簡單通用的主鍵生成器就是uuid。雖然是個(gè)32位難讀的長字符串赂鲤,但是它沒有跨數(shù)據(jù)庫的問題噪径,將來切換數(shù)據(jù)庫極其簡單方便,推薦使用蛤袒!

3熄云、自動(dòng)增長字段類型與序列

數(shù)據(jù)庫

自動(dòng)增長字段

序列

MySQL

Oracle

DB2

MS SQL Server

Sybase

HypersonicSQL

PostgreSQL

SAP DB

HSQLDB

Infomix

4、關(guān)于hilo機(jī)制注意:

hilo算法生成的標(biāo)志只能在一個(gè)數(shù)據(jù)庫中保證唯一妙真。

當(dāng)用戶為Hibernate自行提供連接缴允,或者Hibernate通過JTA,從應(yīng)用服務(wù)器的數(shù)據(jù)源獲取數(shù)據(jù)庫連接時(shí),無法使用hilo练般,因?yàn)檫@不能保證hilo單獨(dú)在新的數(shù)據(jù)庫連接的事務(wù)中訪問hi值表矗漾,這種情況,如果數(shù)據(jù)庫支持序列薄料,可以使用seqhilo敞贡。

5、使用identity摄职、native誊役、GenerationType.AUTO等方式生成主鍵時(shí),只要用到自增字段谷市,數(shù)據(jù)庫表的字段必須設(shè)置成自動(dòng)增加的蛔垢,否則出錯(cuò)。

6迫悠、還有一些方法未列出來鹏漆,例如uuid.hex,sequence-identity等创泄,這些方法不是很常用艺玲,且已被其他方法代替,如uuid.hex鞠抑,官方文檔里建議不使用饭聚,而直接使用uuid方法。

7碍拆、Hibernate的各版本主鍵生成策略配置有略微差別若治,但實(shí)現(xiàn)基本相同。如感混,有的版本默認(rèn)sequence不指定序列名,則使用名為hibernate_sequence的序列礼烈,有的版本則必須指定序列名弧满。

8、還可以自定義主鍵生成策略此熬,這里暫時(shí)不討論庭呜,只討論官方自帶生成策略。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末犀忱,一起剝皮案震驚了整個(gè)濱河市募谎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阴汇,老刑警劉巖数冬,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異搀庶,居然都是意外死亡拐纱,警方通過查閱死者的電腦和手機(jī)铜异,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秸架,“玉大人揍庄,你說我怎么就攤上這事《ǎ” “怎么了蚂子?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缭黔。 經(jīng)常有香客問我食茎,道長,這世上最難降的妖魔是什么试浙? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任董瞻,我火速辦了婚禮,結(jié)果婚禮上田巴,老公的妹妹穿的比我還像新娘钠糊。我一直安慰自己,他們只是感情好壹哺,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布抄伍。 她就那樣靜靜地躺著,像睡著了一般管宵。 火紅的嫁衣襯著肌膚如雪截珍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天箩朴,我揣著相機(jī)與錄音岗喉,去河邊找鬼。 笑死炸庞,一個(gè)胖子當(dāng)著我的面吹牛钱床,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播埠居,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼查牌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了滥壕?” 一聲冷哼從身側(cè)響起纸颜,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绎橘,沒想到半個(gè)月后胁孙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年浊洞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了牵敷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡法希,死狀恐怖枷餐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苫亦,我是刑警寧澤毛肋,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站屋剑,受9級特大地震影響润匙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唉匾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一孕讳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧巍膘,春花似錦厂财、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肪康,卻和暖如春荚恶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磷支。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工谒撼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雾狈。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓嗤栓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親箍邮。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 之前在用Hibernate框架寫東西的時(shí)候叨叙,經(jīng)常會(huì)去寫映射文件hbm.xml锭弊。但是對于主鍵id的一個(gè)generat...
    雅俗共賞M閱讀 817評論 0 2
  • 1.主鍵生成策略 1.1 主鍵的兩種類型 自然主鍵:把數(shù)據(jù)表中的某一業(yè)務(wù)字段作為表的主鍵。如一張用戶表中擂错,把用戶的...
    Wizey閱讀 538評論 0 3
  • Hibernate是一個(gè)開放源代碼的對象關(guān)系映射框架味滞,它對JDBC進(jìn)行了非常輕量級的對象封裝,它將POJO與數(shù)據(jù)庫...
    蘭緣小妖閱讀 1,195評論 1 18
  • 今天來理性的分析下甩鍋人的前生后世 甩鍋的意思相信大家都懂,就是明明可能是自己的責(zé)任剑鞍,但出了問題昨凡,總能怪客觀環(huán)境,...
    兮揚(yáng)閱讀 230評論 0 0
  • 親愛的小主: 您好蚁署,我從來歐洲荷蘭跨海越洋而來便脊,只為一解您的相思,聽說您常常上班癢光戈、下班癢哪痰、看電視也癢,且半夜痛癢...
    魚團(tuán)長閱讀 534評論 1 1