2011-03-17 42 views
29

我使用的是hibernate 3,oracle 10g。我有一張桌子:主題。該定義是這裏hibernate oracle序列產生大缺口

CREATE TABLE SUBJECT 
    ( 
    SUBJECT_ID NUMBER (10), 
    FNAME VARCHAR2(30) not null, 
    LNAME VARCHAR2(30) not null, 
    EMAILADR VARCHAR2 (40), 
    BIRTHDT DATE  not null, 
    constraint pk_sub primary key(subject_id) USING INDEX TABLESPACE data_index 
    ) 
; 
時插入一個新的課題,sub_seq用於創建一個主題ID

,分辨率爲這裏

create sequence sub_seq 
     MINVALUE 1 
     MAXVALUE 999999999999999999999999999 
     START WITH 1 
     INCREMENT BY 1 
     CACHE 100 
     NOCYCLE ; 

Subject類是這樣的:

@Entity 
@Table(name="ktbs.syn_subject") 
public class Subject { 

    @Id 
    @Column(name="subject_id") 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ") 
    @SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ") 
    private long subjectId; 
    private String fname; 
    private String lname; 
    private String emailadr; 
    private Date birthdt; 
} 

在主題表中,數據庫中有4555個主題由excel中的plsql腳本加載,sub_sequence正常工作。主題ID範圍從1-4555。

然而,當我使用Hibernate增加從我的應用程序中的主題, 序列號躍升至255050.運行後,由休眠這個樣子的

270079 
270078 
270077 
270076 
270075 
270074 
270073 
270072 
270071 
270070 
270069 
270068 
270067 
270066 
270065 
270064 
270063 
270062 
270061 
270060 
270059 
270058 
270057 
270056 
270055 
270054 
270053 
270052 
270051 
270050 
265057 
265056 
265055 
265054 
265053 
265052 
265051 
265050 
260059 
260058 
260057 
260056 
260055 
260054 
260053 
260052 
260051 
260050 
255067 
255066 
255065 
255064 
255063 
255062 
255061 
255060 
255059 
255058 
255057 
255056 
255055 
255054 
255053 
255052 
255051 
255050 
4555 
4554 
4553 
. 
. 
. 
. 
1 

生成的被攝體IDS幾天有幾個大缺口:4555至255051,255067至260051,265057至270051

這是一種浪費而不是期望的行爲。

沒有人知道爲什麼會這樣,熱修復它

感謝

回答

36

我認爲這個問題是來自一個事實,即序列發生器是不是一個真正的序列發生器,但序列希洛發電機,用50默認分配大小的文件所示:http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-identifier

這意味着如果序列值是5000,則下一個生成的值將是5000 * 50 = 250000.將序列的緩存值添加到等式中,這可能會解釋您的初始缺口。

檢查序列的值。它應該小於最後生成的標識符。注意不要將序列重新初始化爲最後生成的值+1,因爲生成的值將呈指數級增長(我們遇到了這個問題,並且由於溢出而產生負整數ID)

+0

謝謝。是的,這可能是問題所在。那麼在我的情況下這裏休眠不應該使用oracle定義的序列對象?如何解決這個問題? – sse 2011-03-17 23:31:49

+0

如果我記得安裝正確的話,你也可以從重新啓動中得到間隔,因爲db中的序列是1,2,3,4,如果分配大小是500,那麼當它得到下一個seq時,500 * 1 = 500,當它最後到999,它調用下一個序列檢索2(或3如果另一個進程已經2),然後500 * 2 = 1000一直到1499.服務器重新啓動後,只使用500或500中的值會導致一個溝。 – 2013-12-12 02:57:19

+0

哦,並且當你調用persist並且不刷新時(如果在手動模式下)它使用從未保存到數據庫的序列中的id(有很多原因,因爲我只是注意到你沒有使用allocationSize我們使用ALOT來防止插入操作中的常量db交互,因爲它是更往返工作) – 2013-12-12 02:59:23

5

如果你讀了下面的鏈接,你會看到,這個問題是由您的序列創建命令的緩存設置造成的。刪除緩存設置就能解決問題的程度 - 但並沒有考慮到回滾的方法可行,等等

Link是:http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:369390500346406705

現在重新同步您的序列唯一的辦法就是重新創建序列,重命名當前表並重新創建表,然後將舊錶中的記錄重新插入到新表中。

注意:序列的緩存值對於一次分配'x'序列值的大負載很有用。如果你使用的是一個你一次插入的交易系統 - 那麼緩存是沒有用的(或者我應該說 - 我從來沒有發現它有用)。

注意:這是我對序列的緩存選項的理解。您可以在CREATE SEQUENCE命令中查找Oracle文檔以獲取更多信息。但上面的鏈接應該爲您的問題提供合理的答案。

謝謝。 保羅

+0

謝謝。但差距是10000,並且定義的差距是100.它是否與休眠設置有關? – sse 2011-03-17 22:59:15

+2

每次插入時,它都會分配100個序列值。因此,10,000的缺口只有1,000或100個記錄被插入。您需要閱讀序列緩存以獲取更多詳細信息 - 但重點是您無法依賴序列來維護一組連續的值,因爲無論緩存值如何,空位總是存在。 – PaulJ 2011-03-17 23:01:26

+1

我只是從sql開發人員的查詢從雙重選擇sub_seq.nextval;它顯示5408.這意味着hibernate不使用oracle序列對象sub_seq。我懷疑休眠設置有問題 – sse 2011-03-17 23:13:21

35

同意JB。但還是要感謝PaulJ。

更具體到我下面的註釋代碼:

@Entity 
@Table(name="ktbs.syn_subject") 
public class Subject { 

    @Id 
    @Column(name="subject_id") 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ") 
    @javax.persistence.SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ") 
    private long subjectId; 
    private String fname; 
    private String lname; 
    private String emailadr; 
    private Date birthdt; 
} 

如果使用javax.persistence.SequenceGenerator,使用Hibernate希洛,將有可能創造序列中較大的差距。有一個後解決這一問題: https://forum.hibernate.org/viewtopic.php?t=973682

有解決這個問題

  1. 在SequenceGenerator註釋兩種方式,加入allocationSize = 1, initialValue= 1
  2. 而不是使用javax.persistence.SequenceGenerator,使用有機.hibernate.annotations,像這樣:

    @javax.persistence.SequenceGenerator(
        name = "Question_id_sequence", 
        sequenceName = "S_QUESTION" 
    ) 
    
    @org.hibernate.annotations.GenericGenerator(
        name="Question_id_sequence", 
        strategy = "sequence", 
        parameters = { 
         @Parameter(name="sequence", value="S_QUESTION") 
        } 
    ) 
    

我已經測試了兩種方式,這很好。

+1

謝謝!!!!!!!!!! – Nick 2012-02-24 11:13:52

+0

是的它的工作! – Ajit 2016-05-18 09:41:27

6

另一種解決方案是:

使用 '戰略= GenerationType.AUTO' 而不是'戰略= GenerationType.SEQUENCE,如下圖

@Id 
@SequenceGenerator(name = "studentId", sequenceName = "student_Id") 
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId") 
private int studentId; 
+0

感謝這工作在我的情況 – 2016-10-03 14:55:07

1

最全成的答案是:

@Id 
@SequenceGenerator (name = "id_sequence", sequenceName = "sq50") 
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_sequence") 
public int getId() { 
return id; 
} 
0

正如說here,嘗試調整您的SequenceGenerator.allocationSize與您的數據庫序列INCREMENT BY號碼。

6

實際上,如果您的序列INCREMENT VALUE爲1,並且您不需要保留大量實體,實際上擁有allocationSize = 1就可以了。 但是,如果你想堅持成千上萬或上百萬條記錄,上述設置可能會變成性能瓶頸因爲每次保存需要獲取一個id,因此需要一個db讀取。

爲了解決這個問題,我們需要將allocationSize也設定爲像500和序列INCREMENT VALUE在DB到500,然後最重要的新增休眠設置hibernate.id.new_generator_mappings問它使用新的序列發生器的實現,在這裏,我承擔你在Java配置類設置你的Hibernate屬性:

properties.setProperty("hibernate.id.new_generator_mappings", Boolean.toString(true)); 

這樣,Hibernate將使用SequenceStyleGenerator,而不是老SequenceHiLoGenerator生成的ID。 SequenceStyleGenerator更多jpa和oracle友好。它基於序列式數據庫結構生成標識符值。變體的範圍從實際使用序列到使用表來模仿序列。

看我的文章更多的細節,如果你是在同一條船上:

vcfvct.wordpress。com/2016/04/23/jpa-sequencegenerator-with-allocationsize-1-performance-tuning/

1

我有類似的問題。序列發生器和序列hilo發生器非常相似但有區別。在休眠3中,hilo生成器乘以默認值50.因此,不需要增加DB序列。另一方面,更高版本的hibernate默認使用序列生成器。因此DB需要增加50。

https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/Migration_Guide/Preserve_the_Existing_Behavior_of_the_Hibernate_Identity_Auto_Generated_Value1.html

我有這個問題,它有多個版本的休眠(3和5)。相同的配置工作正常(在數據庫中增加1)。但在hibernate 5中失敗了。因此,我更新了我的persistence.xml,如下所示。這確保hilo代

 <property name="hibernate.id.new_generator_mappings" value="false" />