問題の概要
一見ランダムなタイミングで、「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 の allocationSize 属性のデフォルトは 50 (JPA プロバイダーとして hibernate を使用しています) であるため、create sequence 構文は、allocationSize に一致するようにシーケンスをどれだけインクリメントするか、具体的には 50 ずつ指定する必要があると思います。
この推測に基づいて、コードを次のように変更する必要があると思います。
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) JPA プロバイダーとして hibernate を使用する場合にシーケンス ジェネレーターを使用するためのベスト プラクティスは何ですか?