问题概述
在看似随机的时间我们得到一个例外“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;
...
}
分析
我认为我认识到这个配置有两个问题:
1)@SequenceGenerators都指定相同的名称属性,即使它们应该映射到不同的数据库序列。
2)@SequenceGenerator的allocationSize属性默认为50(我们使用hibernate作为JPA提供者)所以我认为创建序列语法应该指定序列应该增加多少,特别是50以匹配allocationSize。 / p>
根据这个猜测,我认为应该将代码修改为这样的代码:
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提供程序时,使用序列生成器的最佳做法是什么?
答案 0 :(得分:4)
是的,您的分析是正确的。您正确识别了问题(我们遇到了类似的问题)。 并且......如果你要把它投入生产,不要忘记:
initalValue
中的@SequenceGenerator
)。我无法列举最佳实践,但我想你可以降低50的限制。另外我没有PostgreSQL的经验,但在MySQL中你有一个简单的seq表。生成器和休眠使整个东西。
答案 1 :(得分:1)
我有类似的问题。在我的例子中,我直接通过SQL导入数据。这导致了' hibernate_sequence'的问题。 hibernate_sequence是id 123,但我的表中有一行id大于123。
答案 2 :(得分:1)
有同样的问题-出于某种原因,休眠状态未从序列中选择正确的数字。尝试了所有运气不佳的方法,最后得出了这个解决方案:
@Entity
@Table(name = "events")
@SequenceGenerator(name = "events_id_seq", sequenceName = "events_id_seq", allocationSize = 1)
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "events_id_seq")
private BigInteger id;
我不得不将@SequenceGenerator放在类的顶部,而不是方法的顶部,并且分配大小也设置为1(如果将此值保留为默认值,它将开始产生负ID)。
spring-data-jpa 2.1.2
,hibernate 5.3.7
,pg 42.2.5
答案 3 :(得分:0)
我遇到了同样的问题。我试图解决这个问题。也许这不是最好的解决方案,但我希望它现在能解决您的问题。
@SequenceGenerator(schema = "DS_TEST",name = "SEQ_PR_TEXT",sequenceName = "SEQ_PR_TEXT",
allocationSize = 1)
public class TextEntity {
@Id
@GeneratedValue(generator = SequenceConstant.SEQ_PR_TEXT,
strategy = GenerationType.SEQUENCE)
@Column(name = "PR_TEXT_ID")
private Long id;
}