2013-07-24 67 views
6

我已經使用純JPA批註定義了許多Hibernate實體。這些在我的數據庫上使用預定義的Oracle序列來自動生成主鍵值。帶Hibernate的JBoss EAP 6.x Oracle序列主鍵上的重複值

@Id 
@SequenceGenerator(name = "USERS_ID_GENERATOR", sequenceName = "MY_SEQ") 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_ID_GENERATOR") 
@Column(name = "U_ID", updatable = false, unique = true, nullable = false, precision = 19) 
private Long id; 

當這個被部署到JBoss EAP 6.1所有在短期內休眠開始在插入(ORA-00001錯誤)產生重複鍵後最初但效果很好。

我不在乎ID排序或差距,但不能容忍重複的鍵......這裏發生了什麼?

回答

13

這沒有很好的記錄,這裏和其他網站上的許多解決方案都與早期版本的hibernate相關,其中HiLo sequenceGenerator是默認的。但經過調查,我發現的根本原因是,JBoss的EAP 6默認情況下,它使用一個org.org.hibernate.id.enhanced.SequenceStyleGenerator代替舊版本的設置

hibernate.id.new_generator_mappings=true 

Hibernate SequenceStyleGenerator默認增量爲1(檢查代碼!),但是JPA會將此生成器中的增量值重寫爲50.這意味着生成器會查看nextval序列並保留50個ID使用的緩存,從nextval開始 - 49.當這些耗盡時,生成器從oracle讀取下一個序列,並重復該過程。所以一旦第一系列的ID被耗盡,我們開始看到重複的鍵。

所以分辨率是:

1)無論是用50的增量值來定義你的Oracle序列(S)相匹配的JPA默認

CREATE SEQUENCE MY_SEQ 
START WITH 50 
MAXVALUE 9999999999999999999 
INCREMENT BY 50 
NOCYCLE; 

2)添加allocationSize = 1添加到@SequenceGenerator批註中 - 這將強制SequenceGenerator返回從oracle序列中讀取它需要的每個ID的下一個值(可能會對性能產生影響)

@SequenceGenerator(name = "USERS_ID_GENERATOR", sequenceName = "MY_SEQ", allocationSize = 1) 

,或者

3)定義的Oracle序列INCREMENT BY某個其它值,保證了allocationSize匹配。

回答了我自己的問題,希望能幫助別人解決這個問題。

+0

雖然我正在尋找其他信息,但您添加的信息作爲幫助他人獲得+1的答案。 – kosa

1

你的回答是正確的;只是一些更多的細節。

有些帖子建議關閉 hibernate.id.new_generator_mappings = false。

但根據 https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide#JPAReferenceGuide-Persistenceunitproperties

有 GenerationType.AUTO和GenerationType.SEQUENCE

如果選擇自動

之間的差異,你會選擇休眠本地人。 ,如果你選擇SEQUENCE,你會匹配hilo序列分配算法,這是絕對不相同的SequenceStyleGenerator。 如果您切換hibernate.id.new_generator_mappings = true/false,這將不兼容。

所以答案1)肯定是正確的/遵循當前的Hibernate/Jboss建議。

...和答案設置allocationSize = 1到所有實體不是一個好的解決方案。 請參閱 http://itdevworld.wordpress.com/2009/12/20/hibernate-sequencegenerator-with-allocationsize1-leads-to-huge-contention/

+1

謝謝@skay,我已經添加了一個說明來回答2)有關單個分配的潛在性能影響。如果順序設置爲'order',這在RAC環境中尤其明顯。 –

+0

注意 - 鏈接中的JBoss文檔提到這是一個Hibernate 4.x設置。它在Hibernate 3中也得到了支持。在我們的應用程序中將它與3.6.0.Final一起使用。JBoss AS 7隨附4.x,因此它們的文檔如何引用它。 –