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究竟是哪個終端生成的,你可能會說:可以換個字段保存啊?這類問題就智者見智仁者見仁了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章