JPA 2 @SequenceGenerator @GeneratedValue产生唯一约束违规

axi*_*sty 8 java postgresql hibernate jpa

问题概述

在看似随机的时间我们得到一个例外"postgresql重复密钥违反了唯一约束".我确实认为我知道我们的问题是什么,但我不想在没有可重复的测试用例的情况下对代码进行更改.但由于我们无法在生产中随机以外的任何环境中重现它,我正在寻求SO的帮助.

在这个项目中,我们有多个postgres数据库,以及为每个数据库中的每个表配置的主键序列.这些序列是这样创建的:

create sequence PERSONS_SEQ;
create sequence VISITS_SEQ;
etc...
Run Code Online (Sandbox Code Playgroud)

我们使用这些序列为实体生成主键,如下所示:

@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;
  ...
}
Run Code Online (Sandbox Code Playgroud)

分析

我想我认识到这个配置有两个问题:

1)@SequenceGenerators都指定相同的名称属性,即使它们应该映射到不同的数据库序列.

2)@SequenceGenerator allocationSize属性默认为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;
  ...
}
Run Code Online (Sandbox Code Playgroud)

我只是测试这个,而不是在SO上提问,但同样,我们还没有能够在任何其他环境中重现这个生产问题.甚至在生产中,唯一约束违规仅发生在看似随机的时间.

问题:

1)在分析修复此唯一约束违规的更改时,我是否正确?

2)将hibernate用作JPA提供程序时,使用序列生成器的最佳实践是什么?

And*_*i I 5

  1. 是的,您的分析是正确的。您已正确确定问题所在(我们有类似的问题)。而且...如果您要将其投入生产,请不要忘记:

    • 要么为具有正确的初始值/初始ID的新序列生成器手动生成序列表(否则,休眠将从1开始,您将再次获得)
    • 或在代码中设置该值(签initalValue@SequenceGenerator)。
  2. 我无法列举最佳实践,但我想您可以降低50的限制。我也没有PostgreSQL的经验,但是在MySQL中,您有一个简单的seq表。generator和hibernate使整个过程变得完整。