class 可配置項(xiàng)
- native:根據(jù)使用的數(shù)據(jù)庫幫你選擇哪個(gè)值
- 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列為例):
獲得hi值:讀取并記錄數(shù)據(jù)庫的hibernate_unique_key表中next_hi字段的值,數(shù)據(jù)庫中此字段值加1保存大审。
獲得lo值:從0到max_lo循環(huán)取值蘸际,差值為1,當(dāng)值為max_lo值時(shí)徒扶,重新獲取hi值粮彤,然后lo值繼續(xù)從0到max_lo循環(huán)。
根據(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í)不討論庭呜,只討論官方自帶生成策略。