问题概述
在看似随机的时间,我们会收到一个异常“ PostgreSQL重复键违反了唯一约束”。我确实认为我知道我们的问题是什么,但是我不想在没有可重现的测试用例的情况下对代码进行更改。但是由于除了随机生产之外,我们无法在任何环境中复制它,因此我要求SO的帮助。
在这个项目中,我们有多个postgres数据库,并且为每个数据库中的每个表配置了主键序列。这些序列是这样创建的:
create sequence PERSONS_SEQ; create sequence VISITS_SEQ; etc...
我们使用以下序列来为实体生成主键,如下所示:
@Entity @Table(name = "visits") public class Visit { @Id @Column(name = "id") @SequenceGenerator(name = "seq", sequenceName = "visits_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq") private int id; ... } @Entity @Table(name = "person") public class Person { @Id @Column(name = "id") @SequenceGenerator(name = "seq", sequenceName = "persons_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq") private int id; ... }
分析
我认为此配置存在2个问题:
1)两个@SequenceGenerators都指定相同的name属性,即使它们应该映射到不同的数据库序列。
2)@SequenceGenerator distributionSize属性默认为50(我们使用hibernate模式作为JPA提供程序),因此我认为创建序列语法应指定序列应增加多少,特别是增加50才能匹配allocationSize。
基于这种猜测,我认为应该将代码修改为如下形式:
create sequence PERSONS_SEQ increment by 50; create sequence VISITS_SEQ increment by 50; etc... @Entity @Table(name = "visits") public class Visit { @Id @Column(name = "id") @SequenceGenerator(name = "visits_seq", sequenceName = "visits_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "visits_seq") private int id; ... } @Entity @Table(name = "person") public class Person { @Id @Column(name = "id") @SequenceGenerator(name = "persons_seq", sequenceName = "persons_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "persons_seq") private int id; ... }
我只是测试一下,而不是问SO的问题,但是同样,我们还无法在任何其他环境中重现此生产问题。甚至在生产中,唯一约束违反也只会在看似随机的时间发生。
问题:
1)我在分析更改以解决此唯一约束冲突方面是否正确?
2)将hibernate用作JPA提供程序时,使用序列生成器的最佳实践是什么?
是的,您的分析是正确的。您已正确确定问题所在(我们有类似的问题)。而且…如果您要将其投入生产,请不要忘记:
initalValue
@SequenceGenerator