1. 程式人生 > >JPA使用Hibernate實現,使用UUID.主鍵的生成策略.

JPA使用Hibernate實現,使用UUID.主鍵的生成策略.

警告資訊如下:

3.1 WARN  [org.hibernate.id.UUIDHexGenerator] (ServerService Thread Pool -- 48) HHH000409:Using org.hibernate.id.UUIDHexGenerator which does not generate IETF RFC 4122 compliant UUID values; consider using org.hibernate.id.UUIDGenerator instead

修改 @GenericGenerator(name = "system-uuid", strategy = "uuid") 為@GenericGenerator(name = "system-uuid", strategy = "uuid2")

下面是在CSDN上看到的一篇文章,儲存在我的txt中,現在也貼出來.

介紹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中變數控制具體的生成策略(因為符合RFC4122定義,所以避免了警告資訊) 



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