2010-09-02 103 views
1

我正在使用休眠sequencegenerator爲我的主鍵列自動生成唯一值。示例代碼如下。休眠序列生成非連續值

@Entity 
@Table(name = "REQUEST") 
@javax.persistence.SequenceGenerator(name = "REQ_SEQ", sequenceName = "REQUEST_SEQ") 
public class Request { 
/** 
* Unique id for this request 
*/ 
@Id 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REQ_SEQ") 
@Column(name = "REQ_ID") 
private long requestId; 
    //So on 
} 

一切工作正常,除了生成的值交錯的事實。例如,它插入5000到5015(15個插入)的值,然後第16個插入的值爲5100.然後,對於一些後續插入以及再次出現的問題,它可以正常工作。 我沒有任何問題,只要生成的值是唯一的,但只是想知道什麼可能導致此問題。僅供參考,我正在使用Oracle。

+0

這其實不是hibernate相關的問題,而是一個Oracle數據庫的問題。這一切都取決於你的序列是如何創建的。 – 2010-09-02 06:26:52

+0

你有多確定系統中沒有其他人使用相同的序列? – 2010-09-02 06:29:08

+0

這是一個開發服務器,正在重新開始休息發生的地方?看起來發生器impl是一個hilo,一次在內存中保留100個密鑰。 – Affe 2010-09-02 06:31:14

回答

9

Oracle序列以這種方式工作。他們只保證唯一性,但他們不保證連續的值,因爲它會妨礙並行性。

他們在內部做的或多或少是這樣的:當您請求序列中的下一個值時,Oracle會預先計算一大塊值(在您的情況下爲5000-5099)並將其放入序列緩存中,然後設置seq .nextval =磁盤上5100。但是,如果由於活動,數據庫必須從緩存中丟棄大量值,那麼當下次訪問seq.nextval時,它會佔用另一個塊5100-5199。也就是說,Oracle甚至不會嘗試保存已放入緩存的序列值。

這個問題的關鍵在於,序列緩存是一種內存結構,它的速度更快,並且與磁盤上的結構本身的序列本身更具可並行性。隨着我們想要擴大規模,我們希望儘可能避免進入磁盤。

您可以使用CACHE子句中的順序控制塊尺寸爲給定的順序DDL:

CREATE SEQUENCE seq2 
CACHE 50; 
+0

什麼是最佳塊大小。較低的塊大小是否會影響性能?謝謝(你的)信息。 – chedine 2010-09-02 06:41:37

+1

@gpeche不應該讓ddl命令留給JPA獨立於數據庫嗎? – stacker 2010-09-02 06:54:11

+2

沒有最佳的'CACHE'大小。較小的'CACHE'值會影響性能,因爲Oracle必須更頻繁地使用磁盤/緩衝區緩存。但真正的命中是並行的,因爲從緩存中獲取序列值比直接從序列中獲取序列值更可並行化。 'CACHE'的默認值是20,往往*太低*。至少在數百人中,你會希望它有一個相當繁忙的序列。但是,一如既往,**先測量**。 此外,請參閱http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:6393918681776/thread.jspa?threadID=552069 – gpeche 2010-09-02 07:02:54

0

從Oracle文檔:

CREATE SEQUENCE customers_seq 
    START WITH 1000 
    INCREMENT BY 1 
    NOCACHE; 

的NOCACHE關鍵字是您可以使用的,如果你會喜歡相應的一系列ID。當然,正如前面的評論所解釋的那樣,這會限制序列吞吐量,並可能阻礙您的應用程序性能。