8

我已经使用纯 JPA 注释定义了许多 Hibernate 实体。它们在我的数据库上使用预定义的 Oracle 序列来自动生成主键值。

@Id
@SequenceGenerator(name = "USERS_ID_GENERATOR", sequenceName = "MY_SEQ")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_ID_GENERATOR")
@Column(name = "U_ID", updatable = false, unique = true, nullable = false, precision = 19)
private Long id;

当它被部署到 JBoss EAP 6.1 时,最初一切正常,但是在短时间内,Hibernate 开始在插入时生成重复键(ORA-00001 错误)。

我不关心 id 排序或间隙,但不能容忍重复的键......这里发生了什么?

4

2 回答 2

14

这没有很好的记录,这里和其他站点上的许多解决方案都与 HiLo 序列生成器是默认的旧版本的休眠有关。但经过调查我发现根本原因是 JBoss EAP 6 集

hibernate.id.new_generator_mappings=true 

默认情况下,它使用 org.org.hibernate.id.enhanced.SequenceStyleGenerator 而不是旧版本。

Hibernate SequenceStyleGenerator 默认增量为 1(检查代码!),但是 JPA 将此生成器中的增量值覆盖为 50。这意味着生成器查看序列 nextval 并保留 50 个 id 的缓存以供使用,从 nextval 开始 - 49. 当这些用完时,生成器从 oracle 读取下一个序列,并重复该过程。因此,一旦第一个系列的 id 用完,我们就会开始看到重复的键。

所以决议是:

1) 使用增量值 50 定义您的 Oracle 序列以匹配 JPA 默认值

CREATE SEQUENCE MY_SEQ
START WITH 50
MAXVALUE 9999999999999999999
INCREMENT BY 50
NOCYCLE;

或者

2) 将 allocationSize=1 添加到 @SequenceGenerator 注释 - 这会强制 SequenceGenerator 返回以从 oracle 序列中读取它需要的每个 ID 的下一个值(具有潜在的性能影响)

 @SequenceGenerator(name = "USERS_ID_GENERATOR", sequenceName = "MY_SEQ", allocationSize = 1)

, 或者

3) 定义 Oracle 序列 INCREMENT BY 某个其他值,并确保 allocationSize 匹配。

回答了我自己的问题,希望能帮助解决这个问题的其他人。

于 2013-07-24T05:17:49.020 回答
1

你的答案是正确的;只是更多的细节。

有些帖子建议关闭 hibernate.id.new_generator_mappings=false。

但根据 https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide#JPAReferenceGuide-Persistenceunitproperties

GenerationType.AUTO 和 GenerationType.SEQUENCE 之间有区别

如果您选择AUTO,您将选择hibernate native。如果您选择 SEQUENCE,您将匹配 hilo 算法进行序列分配,这与 SequenceStyleGenerator 绝对不同。如果您切换 hibernate.id.new_generator_mappings=true / false,这将不兼容。

所以答案 1) 绝对是正确的 / 遵循当前的 Hibernate/Jboss 建议。

...并且为所有实体设置 allocationSize=1 的答案不是一个好的解决方案。请参阅 http://itdevworld.wordpress.com/2009/12/20/hibernate-sequencegenerator-with-allocationsize1-leads-to-huge-contention/

于 2013-09-26T20:21:44.070 回答