Hibernate标识符属性(主键)生成策略全析
??? 數(shù)據(jù)庫中的主鍵能夠唯一識別一條記錄,它可以是一個字段也可以是多個字段的組合。主鍵的主要作用是標識表中的一條記錄,還有和其他表中的數(shù)據(jù)進行關(guān)聯(lián)。數(shù)據(jù)庫中的主鍵類型必須符合唯一性約束和非空約束。作為附加屬性,主鍵應該盡可能簡潔,不要包含過多屬性。根據(jù)這個原則,主鍵可以分為自然主鍵和代理主鍵。
??? 自然主鍵是數(shù)據(jù)表中有邏輯含義的字段,比如身份證號來唯一確定一條個人記錄。也可以通過學號和課程號來唯一確定成績。使用自然主鍵時如果業(yè)務發(fā)生變化則對數(shù)據(jù)庫調(diào)整是極其麻煩的,所以數(shù)據(jù)庫設計使用代理主鍵是非常好的選擇。代理主鍵是一個和業(yè)務無關(guān)的流水號,一般采用數(shù)據(jù)庫中自動增長的機制自動生成。例如Oracle數(shù)據(jù)庫使用序列,MySQL和SQL Server有自動增長(auto increment)類型,該字段類型一般為Integer,名稱設置為ID或XXID。下面來看看Hibernate中的主鍵生成策略,實驗都以Oracle為主,MySQL為輔來說明。
??? 第一種是increment策略,Hibernate配置如下:
??? 運行結(jié)果如下:
??? 可以看出,Hibernate是從數(shù)據(jù)庫中先找出已經(jīng)存在的最大主鍵數(shù)值,然后加1后作為新紀錄的主鍵再執(zhí)行插入語句。這種策略不適合非獨享數(shù)據(jù)庫或者分布式的Hibernate應用,否則就很難保證主鍵值的唯一了。
??? 第二種是identity策略,Hibernate中配置如下:
??? 這種策略在Oracle中無法使用,因為這種策略是針對數(shù)據(jù)庫中字段自動增長類型。改在MySQL中測試,得到如下結(jié)果:
??? 多次運行程序,在數(shù)據(jù)庫中查看,可以看到主鍵是自動進行遞增的。
??? 第三種是sequence策略,Hibernate中配置如下:
??? 使用序列策略是,需要現(xiàn)在數(shù)據(jù)庫中創(chuàng)建一條序列,運行程序,得到如下結(jié)果:
??? 可以看出Hibernate先從序列中得到下一個數(shù)值,然后執(zhí)行插入操作。
??? 第四種是hilo策略,這是Hibernate采用一種稱為“高/低位”(hi/lo)的算法產(chǎn)生標識符屬性值,該算法采用一個高位值和一個低位值進行運算,結(jié)果作為標識符屬性的值。使用該策略時,需要在數(shù)據(jù)庫中建立一個表和其中一個字段,名稱可以自定。其中的字段值作為高位值的來源。在Hibernate中配置如下:
??? 可以見名知意,我使用的表名是HIBERNATE_KEY,字段名是NEXT_HIVALUE,然后給該字段設置一個值,作為高位。低位Hibernate有自己的管理機制可不用創(chuàng)建,也可以給出在配置文件中用<param name="max_lo">1</param>的形式給出即可,一般使用情況下使用1更好。該算法是每次按max_lo數(shù)值遞增。Hibernate的執(zhí)行結(jié)果還是一條語句,如下:
??? 執(zhí)行后高位自動加1,然后到數(shù)據(jù)庫中就可以查看生成的主鍵數(shù)值。該策略與底層的數(shù)據(jù)庫無關(guān),只要保證高位降低,那么生成的主鍵值是唯一的,并且可跨數(shù)據(jù)庫使用。
??? 第五種是seqhilo策略,基于hilo策略,這種方式的標識符屬性生成時指定一個序列作為高位值,那么在Hibernate中的配置如下:
??? 執(zhí)行插入后,Hibernate首先取出序列的下一個值作為高位值,然后計算一個ID出來進行操作,得到如下結(jié)果:
??? 第六種是uuid策略,這種策略是使用128位的UUID算法來生成字符串類型標識符屬性,這種算法使用IP地址,JVM的啟動時間(精確到1/4秒),系統(tǒng)時間和一個計數(shù)器(在當前JVM中唯一)這些數(shù)值經(jīng)過計算得到一個標識符屬性的值,產(chǎn)生的值是32位長度的字符串,則使用前需要將數(shù)據(jù)庫字段調(diào)整到varchar2(32),持久化類的ID屬性改為String進行測試。Hibernate中配置如下,注意字段信息的修改:
??? 執(zhí)行后Hibernate的結(jié)果還是一條插入語句,這里不再復制了,我們看看數(shù)據(jù)庫中的結(jié)果吧,如下圖,就得到了32位的主鍵值了。
??? 在做文件下載時,用這種策略生成的主鍵就可以作為下載鏈接,而不用在人為去制作鏈接,是一個不錯的選擇。
??? 第七種是guid策略,Hibernate中配置如下:
??? 這個在Oracle中是用了sys_guid()函數(shù)生成的值,而在MySQL中使用uuid()函數(shù)生成值,這個值要設置成varchar2/varchar類型,區(qū)別在于Oracle中是32位長度,而MySQL原生是36位(有4個-隔開)。運行程序得到如下結(jié)果:(Oracle環(huán)境下)
(MySQL環(huán)境下)
??? 第八種是native策略,native字面意思是“本地的”,那么對于數(shù)據(jù)庫,Hibernate該如何選擇呢?Hibernate根據(jù)所使用的數(shù)據(jù)庫支持能力從identity,sequence或者hilo策略中選擇一種,Hibernate中配置很簡單:
??? 在Oracle下,Oracle先創(chuàng)建一個序列,使用默認名(數(shù)據(jù)庫名_SEQUENCE),然后執(zhí)行插入操作,而在MySQL下則使用identity策略,使用了自動增長的字段。Oracle中測試結(jié)果如下:
??? 第九種是assigned策略,這種方式也是Hibernate中<generator>沒有配置標識符屬性生成策略時默認使用的方式。但使用這種策略時需要我們自定義標識符屬性的值,也就是我們?nèi)藶樵O置標識符屬性的值,這就需要在程序中顯式為標識符屬性(ID)賦值。配置方式如下:
??? 第十種是foreign策略,這種方式是通過關(guān)聯(lián)的持久化對象為當前的持久化對象設置標識符屬性,當他們是一對一關(guān)聯(lián)時,一個持久化類的主鍵值可以參考關(guān)聯(lián)持久化類的標識符屬性值。我們做一個完整的實例來看。(使用Hibernate為我們自動創(chuàng)建表)?
?
??? 最后來說一下標識符屬性生成策略的選擇方式。應用不需要分布式時,在數(shù)據(jù)庫支持的sequence,identity,hilo,seqhilo和uuid中選擇比較好。而分布式數(shù)據(jù)庫應用中uuid是最佳選擇。若是改造遺留系統(tǒng),那么使用assigned是最合適的了
總結(jié)
以上是生活随笔為你收集整理的Hibernate标识符属性(主键)生成策略全析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 跟我学Spring3(8.2):对ORM
- 下一篇: 基于hibernate实现的分页技术