具有Hibernate的JBoss EAP 6.x主键上的Oracle序列重复值

sho*_*ser 7 oracle hibernate jpa sequence wildfly

我已经使用纯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;
Run Code Online (Sandbox Code Playgroud)

当它部署到JBoss EAP 6.1时,一切都运行良好,但是在短时间内Hibernate开始在插入上生成重复键(ORA-00001错误).

我不关心id的排序或差距,但不能容忍重复的密钥......这里发生了什么?

sho*_*ser 13

这没有很好的文档记录,这里和其他站点的许多解决方案都与hibernate的旧版本相关,其中HiLo sequenceGenerator是默认的.但经过调查,我发现其根本原因是JBoss EAP 6套装

hibernate.id.new_generator_mappings=true 
Run Code Online (Sandbox Code Playgroud)

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

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

所以决议是:

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

CREATE SEQUENCE MY_SEQ
START WITH 50
MAXVALUE 9999999999999999999
INCREMENT BY 50
NOCYCLE;
Run Code Online (Sandbox Code Playgroud)

要么

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

 @SequenceGenerator(name = "USERS_ID_GENERATOR", sequenceName = "MY_SEQ", allocationSize = 1)
Run Code Online (Sandbox Code Playgroud)

, 要么

3)定义Oracle序列INCREMENT BY其他一些值,并确保allocationSize匹配.

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