使用Oracle序列的Hibernate没有使用它。

24

我已经配置了Hibernate以使用Oracle序列。 序列的缓存大小为20,递增量为1。

一切都正常,Hibernate可以持久化实体。 但是ID值很奇怪:50、51……76、201、202……209、1008、1009、5129、5130等。

如果我要求序列的值(从dual中选择hibernate_sequence.nextval),我得到的值是2、3、4等。

如果我打开Hibernate SQL调试,有时会调用“select hibernate_sequence.nextval from dual”,但由Hibernate分配给ID的数字并不依赖于序列!

@Id
@Column(name = "ID", insertable = false, updatable = false)
@SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "HIBERNATE_SEQUENCE")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceIdGenerator")
private Long id;
3个回答

37
这是因为SequenceGenerator实际上并不是一个序列生成器,而是一个序列hi-lo生成器。这意味着第一次调用它时,它会从序列中获取下一个值(例如6),然后将该值乘以50并给出结果(300)。下一次调用它时,它将返回301(而不是去查找序列),直到达到349。然后它会向序列请求下一个值并获得7,再次将其乘以50以给出350。我的算法描述可能有误,但你可以理解其中的意思。
如果你停止并重新启动应用程序,则会产生间隙。但它比纯序列生成器更有效,因为它只在50代中进行一次数据库调用。
详情请参见http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-enhanced-optimizershttp://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-generator

11
每次递增50不是必须的,这只是默认设置。使用@SequenceGenerator(name="SEQ_ID",sequenceName="SEQ_ID", allocationSize=1)来实现每次仅递增1。allocationSize是关键。 - dseibert
3
有没有不使用这个的方式? 由于其他触发器也在使用这个表格相同的序列,这给我带来了很大问题。他们将来可能会遇到这个数字,对吧? - Anders Metnik
看一下你上面的评论。使用allocationSize。 - JB Nizet
哇,谢谢你的答案。听起来就像 Hibernate 重新发明了 Oracle 的序列缓存... - Jeffrey Kemp

8
我理解你的问题是数据库中ID列的值不是自然序列,但为什么会出现间隙。一些背景信息如下:
- 每次调用`select HIBERNATE_SEQUENCE.nextval from DUAL`时,序列的值都会增加。 - 如果你的序列名称是通用的而不是特定于表的,则如果多个实体都使用HIBERNATE_SEQUENCE作为ID生成器,则序列的值将在所有实体中使用。 - 如果其他应用程序使用HIBERNATE_SEQUENCE,则该值也会被跳过。 - 由于你使用了CACHE=20,Oracle会以20个块为单位获取序列号,然后使用内部缓存返回这些数字。如果缓存丢失(例如,如果DB关闭),则可能会导致跳过数字。 - 如果从数据库中删除行,则序列值不会更改。
例如,考虑以下情况:
你有两个实体Entity1和Entity2,它们都使用HIBERNATE_SEQUENCE作为ID生成器:
- 当前的HIBERNATE_SEQUENCE值为100 - 插入一个Entity1(使用HIBERNATE_SEQUENCE返回101) - 插入一个Entity2(使用HIBERNATE_SEQUENCE返回102) - 插入一个Entity2(使用HIBERNATE_SEQUENCE返回103) - ID为103的Entity2被删除 - 手动执行`select HIBERNATE_SEQUENCE.nextval from DUAL`(返回104) - 插入一个Entity1(使用HIBERNATE_SEQUENCE返回105) - 插入一个Entity2(使用HIBERNATE_SEQUENCE返回106)
因此,最终你会有:
- 具有ID(101、105)的Entity1 - 具有ID(102、106)的Entity2
这就解释了间隙的原因。
编辑:
即使@SequenceGenerator设置使用SequenceGenerator而不是SequenceHiLoGenerator(如JB Nizet所指出的那样,我认为这是间隙的更好解释),序列生成的ID间隙是常见的现象。

-2
CREATE SEQUENCE SEQ_SEQUENCENAME INCREMENT BY 1 START WITH 1 MINVALUE 1;
grant all on SEQ_SEQUENCENAME to public;

@Id
@Column(name = "ID", unique = true, nullable = false)
@SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "SEQ_SEQUENCENAME")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceIdGenerator")
private int Id;

请描述您的答案,而不是复制粘贴 - stinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接