簡體   English   中英

Hibernate,@ SequenceGenerator和allocationSize

[英]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用於以下策略

請查看http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence

@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;

這解決了我的兩個問題:

  1. 已棄用的警告已修復
  2. 現在根據oracle序列生成id。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM