[英]@SequenceGenerator's initValue and allocationSize are ignored and generator not assigned to @Id field (H2, HIbernate, Spring)
[英]Hibernate, @SequenceGenerator and allocationSize
我們都知道使用@SequenceGenerator
時Hibernate的默認行為 - 它將實際數據庫序列增加1 ,將此值乘以50(默認的allocationSize
值) - 然后將此值用作實體ID。
這是不正確的行為,並與規范沖突說:
allocationSize - (可選)從序列中分配序列號時的增量。
要明確:我不打算生成ID之間的差距。
我關心的是與底層數據庫序列不一致的 ID。 例如:任何其他應用程序(例如使用普通JDBC)可能希望在從序列獲取的ID下插入新行 - 但所有這些值可能已被Hibernate使用! 瘋狂。
有人知道這個問題的任何解決方案(沒有設置allocationSize=1
,從而降低性能)?
編輯:
說清楚。 如果最后插入的記錄具有ID = 1
,則HB同時使用值51, 52, 53...
用於其新實體BUT:數據庫中的序列值將被設置為2
。 當其他應用程序使用該序列時,這很容易導致錯誤。
另一方面:規范說(根據我的理解)數據庫序列應該設置為51
,同時HB應該使用范圍2, 3 ... 50
更新:
正如Steve Ebersole在下面提到的那樣:通過設置hibernate.id.new_generator_mappings=true
可以啟用我描述的行為(也是最直觀的行為)。
謝謝大家。
更新2:
對於未來的讀者,您可以在下面找到一個有效的例子。
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ")
@SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS")
private Long id;
}
persistence.xml中
<persistence-unit name="testPU">
<properties>
<property name="hibernate.id.new_generator_mappings" value="true" />
</properties>
</persistence-unit>
為了絕對清楚...你的描述不以任何方式規范沖突。 該規范討論了Hibernate為您的實體分配的值,而不是實際存儲在數據庫序列中的值。
但是,可以選擇獲取您正在尋找的行為。 首先看看我的回復是否有辦法使用JPA注釋和Hibernate動態選擇@GeneratedValue策略? 這將為您提供基礎知識。 只要您設置為使用SequenceStyleGenerator,Hibernate將使用SequenceStyleGenerator中的“池化優化器”來解釋allocationSize
。 “池化優化器”用於允許在序列創建時使用“增量”選項的數據庫(並非所有支持序列的數據庫都支持增量)。 無論如何,請閱讀那里的各種優化策略。
allocationSize=1
在獲取查詢之前它是一個微優化Hibernate嘗試在allocationSize的范圍內分配值,因此盡量避免查詢數據庫的序列。 但是如果將其設置為1,則每次都會執行此查詢。這幾乎沒有任何區別,因為如果您的數據庫被其他應用程序訪問,那么如果另一個應用程序同時使用相同的ID,則會產生問題。
下一代Sequence Id基於allocationSize。
通過defualt它被保持為50
太多了。 只有在一個會話中有大約50
條記錄沒有持久存在並且將使用此特定會話和轉換持續存在時,它也將有所幫助。
因此,在使用SequenceGenerator
時應始終使用allocationSize=1
。 對於大多數底層數據庫,序列總是遞增1
。
Steve Ebersole和其他成員,
你能否解釋一個有更大差距的id的原因(默認為50)? 我正在使用Hibernate 4.2.15並在org.hibernate.id.enhanced.OptimizerFactory cass中找到以下代碼。
if ( lo > maxLo ) {
lastSourceValue = callback.getNextValue();
lo = lastSourceValue.eq( 0 ) ? 1 : 0;
hi = lastSourceValue.copy().multiplyBy( maxLo+1 );
}
value = hi.copy().add( lo++ );
每當它到達if語句的內部時,hi值變得越來越大。 因此,在頻繁重啟服務器的測試過程中,我的id會生成以下序列ID:
1,2,3,4,19,250,251,252,400,550,750,751,752,850,1100,1150。
我知道你已經說它與規范沒有沖突,但我相信對於大多數開發者來說這將是非常意想不到的情況。
任何人的意見都會有所幫助。
Jihwan
更新:ne1410s:感謝您的編輯。
克里克:好的。 我去做。 這是我在這里的第一篇文章,不知道如何使用它。
現在,我更好地理解為什么maxLo用於兩個目的:由於hibernate一次調用DB序列,繼續增加Java級別的id,並將其保存到DB,Java級別id值應該考慮在沒有調用的情況下改變了多少下次調用序列時的DB序列。
例如,序列id在某一點為1,而休眠則為5,6,7,8,9(其中allocationSize = 5)。 下次,當我們得到下一個序列號時,DB返回2,但是hibernate需要使用10,11,12 ...所以,這就是為什么“hi = lastSourceValue.copy()。multiplyBy(maxLo + 1)”是用於從DB序列返回的2中獲取下一個id 10。 在頻繁的服務器重啟期間似乎只是困擾的事情,這是我的問題與更大的差距。
因此,當我們使用SEQUENCE ID時,表中插入的id將與DB中的SEQUENCE編號不匹配。
在深入了解hibernate源代碼之后,在50次插入之后,下面的配置將轉到Oracle db以獲取下一個值。 因此,每次調用時,使INST_PK_SEQ增量為50。
Hibernate 5用於以下策略
@Id
@Column(name = "ID")
@GenericGenerator(name = "INST_PK_SEQ",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@org.hibernate.annotations.Parameter(
name = "optimizer", value = "pooled-lo"),
@org.hibernate.annotations.Parameter(
name = "initial_value", value = "1"),
@org.hibernate.annotations.Parameter(
name = "increment_size", value = "50"),
@org.hibernate.annotations.Parameter(
name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "INST_PK_SEQ"),
}
)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INST_PK_SEQ")
private Long id;
我會檢查DDL中的模式中的序列。 JPA實現僅負責創建具有正確分配大小的序列。 因此,如果分配大小為50,那么您的序列在其DDL中必須具有50的增量。
這種情況通常可以通過創建具有分配大小1的序列然后配置為分配大小50(或默認值)但序列DDL未更新而發生。
我也在Hibernate 5中遇到過這個問題:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
@SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE)
private Long titId;
收到如下警告:
發現使用不推薦使用的[org.hibernate.id.SequenceHiLoGenerator]基於序列的id生成器; 請改用org.hibernate.id.enhanced.SequenceStyleGenerator。 有關詳細信息,請參閱“休眠域模型映射指南”。
然后將我的代碼更改為SequenceStyleGenerator:
@Id
@GenericGenerator(name="cmrSeq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "SEQUENCE")}
)
@GeneratedValue(generator = "sequence_name")
private Long titId;
這解決了我的兩個問題:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.