2010-09-02 99 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。当然,正如前面的评论所解释的那样,这会限制序列吞吐量,并可能阻碍您的应用程序性能。