Hibernate 主鍵生成策略選擇

openkk 12年前發布 | 37K 次閱讀 Hibernate 持久層框架

介紹hibernate主鍵生成策略的文章網上比比皆是。但是如何選擇一個適合于自己項目的主鍵生成策略缺沒有什么好的指導性文章。在此希望與大家議論。
hibernate的主鍵生成策略主要包括了"uuid2","guid","uuid","uuid.hex","hilo","assigned","identity","select","sequence","seqhilo","increment","foreign","sequence- identity","enhanced-sequence","enhanced-table",全部在 org.hibernate.id.factory.DefaultIdentifierGeneratorFactory中定義,至于每種生成策略的簡單描述不是本文重點議論的話題,我們主要將著眼點放到各生成器的優缺點上去(當然都有優點只是適合不適合,本文就想議論這個)
hibernate主鍵生成采用策略模式進行設計,各個生成策略都直接或或者間接實現了IdentifierGenerator接口,此接口只有一個方法 publicSerializablegenerate(SessionImplementorsession,Objectobject)throwsHibernateException; 這個方法由各個類實現具體的生成邏輯。
我們來一個一個看一下:
1、uuid2,IdentifierGenerator的實現類是UUIDGenerator,具體由UUIDGenerationStrategy策略負責生成,它有兩個實現StandardRandomStrategy和CustomVersionOneStrategy,他們都是使用 java.util.UUID的api生成主鍵的,StandardRandomStrategy最終由UUID.randomUUID();生成,而 CustomVersionOneStrategy則采用版本號與位運算通過構造函數 newUUID(mostSignificantBits,leastSignificantBits);生成。
特點是:不需要和數據庫交互,可根據RFC4122定義的5中變量控制具體的生成策略

2、guid,IdentifierGenerator的實現類是GUIDGenerator,通過 session.getFactory().getDialect().getSelectGUIDString();獲得各個數據庫中的標示字符串,mySql用"selectuuid()";oracle9g用 return"selectrawtohex(sys_guid())fromdual";其他看源碼吧。
特點是:需要和數據庫進行一次查詢才能生成。數據庫全局唯一。

3、uuid和uuid.hex 兩個一個東西。IdentifierGenerator的實現類是UUIDHexGenerator,通過 StringBuffer(36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep).append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep).append(format(getCount())) 生成。
特點:不需要和數據庫交互,全網唯一。

4、hilo,IdentifierGenerator的實現類TableHiLoGenerator,邏輯較為復雜,通過高低位酸腐生成,但是需要給定表和列作為高值的源。加上本地的地位計算所得。復雜有興趣看"數據建模101"(Ambler,2002)
特點;需要和數據庫交互,全數據庫唯一,與guid不同的是,在標識符的單個源必須被多個插入訪問時可以避免擁堵。

5、assigned IdentifierGenerator的實現類Assigned,沒有生成邏輯,如果為空就拋出異常。
特點:不需要和數據庫交互,自己管理主鍵生成,顯示的指定id.

6、identity,IdentityGenerator并沒有直接實現IdentifierGenerator,而是擴展了 AbstractPostInsertGenerator,并實現PostInsertIdentifierGenerator,而 PostInsertIdentifierGenerator實現了IdentifierGenerator. 通過IdentifierGeneratorHelper類生成,這個比較特殊,它返回是個常量"POST_INSERT_INDICATOR",指在數據庫插入后時生成,然后返回數據庫生成的id,還有個常量"SHORT_CIRCUIT_INDICATOR",是用外鍵 ForeignGenerator時使用的。
特點:需要和數據庫交互,數據插入后返回(反查)id,同一列唯一

7、select, SelectGenerator擴展了AbstractPostInsertGenerator實現了Configurable接口,而 AbstractPostInsertGenerator實現了PostInsertIdentifierGenerator。所以具有和 identity類似的行為,有數據庫觸發器生成。
特點:需要和數據庫交互,

8、sequence,SequenceGenerator實現了PersistentIdentifierGenerator接口,和 Configurable接口,PersistentIdentifierGenerator接口擴展IdentifierGenerator接口,通過數據庫不同獲取不同的取值語句dialect.getSequenceNextValString( sequenceName );然后進行查詢,緩存到IntegralDataTypeHolder中,通過generateHolder( session ).makeValue();獲得。
特點:需要和數據庫交互(但不是每次都是)。sequence唯一

9、seqhilo,擴展了SequenceGenerator,處理邏輯和hilo相同,值不過是使用一個具名的數據庫序列來生成高值部分。
特點:同4

10、increment,IdentifierGenerator的實現類IncrementGenerator,并實現了Configurable接口。數據庫啟動時查詢表的最大主鍵列支,并通過IntegralDataTypeHolder緩存。插入一條,它自加一。
特點:僅需要首次訪問數據庫。

11、foreign,IdentifierGenerator的實現類ForeignGenerator,通過給定的entityName和propertyName查詢獲得值。
特點:需要和數據庫訪問。

后面的幾種基本上是上面各種邏輯的組合,不在一一分析了。enhanced-table是通過數據庫中的表生成id的。


從上面可以看到,雖然這么多,但是大體可以分為三類
1、不需要和數據庫交互就可以生成id的。包括uuid,uuid2,uuid.hex
2、需要和數據庫交互以生成id的。guid,hilo,identity,select,sequence,seqhilo,increment、foreign
  可細分為一個id一個sql:guid,identity,select,foreign
  一個sql多個id:hilo,sequence,seqhilo,increment
3、不用交互我自己管理assigned

提高系統新能的主要做法就是顯著減少數據庫的訪問次數。通過上面的分析,可作為我們考慮的一個指標。
大家議論下,自己項目中的主鍵生成是什么策略,以及優缺點是什么?


這是為csdn的大牛ldh911的議論以下繼續
◎ 關于ID生成
—— 我一貫認為入手都是Assigned,也就是說我考慮的方式是:如果我自己來生成這個ID的話,最優選擇是啥?然后再看看Hibernate之類的是否能提供我最優選擇所期望的。
—— 是否集群環境?是第一個要考慮的因素,但基本上我都以集群環境為必要條件;
—— 然后是:超高并發生成?超高并發查詢?ID是否需要存在語義?等問題。

◎ 不同的ID對我來說有啥區別?
—— UUID:極其適用于分布式計算環境(超越集群了),但ID將不能承載任何語義,高并發生成支持較好,超高并發查詢存在數據庫端不易優化的問題。
—— 數據庫端seq:適用于集群環境,ID可承載某些語義(比如生成時間上較大范圍的先后順序),超高并發生成較搓,超高并發查詢可做特定分區優化。

◎ 最終呢?
—— 最終基本上都選擇UUID或其變體,因為有時候我還是需要ID承載少量語義的,比如我可能會關心這個UUID究竟是哪個終端生成的,你可能會說:可以換個字段保存啊?這類問題就智者見智仁者見仁了。

轉自:http://blog.csdn.net/gudong2945/article/details/7325255

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!