我使用纯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的排序或差距,但不能容忍重复的密钥......这里发生了什么?
答案 0 :(得分:13)
这里没有很好的文档记录,这里和其他网站上的许多解决方案都与hibernate的旧版本相关,其中HiLo sequenceGenerator是默认版本。但经过调查,我发现其根本原因是JBoss EAP 6设置
hibernate.id.new_generator_mappings=true
默认情况下,它使用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;
或
2)在@SequenceGenerator注释中添加allocationSize = 1 - 这会强制SequenceGenerator返回从oracle序列中读取其所需的每个ID的下一个值(具有潜在的性能影响)
@SequenceGenerator(name = "USERS_ID_GENERATOR", sequenceName = "MY_SEQ", allocationSize = 1)
,或
3)定义Oracle序列INCREMENT BY其他一些值,并确保allocationSize匹配。
回答了我自己的问题,希望能帮助其他人解决这个问题。
答案 1 :(得分:1)
你的答案是正确的;更多细节。
有些帖子建议关闭 hibernate.id.new_generator_mappings =假。
之间存在差异 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/