9

問題の概要

一見ランダムなタイミングで、「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 を使用する場合にシーケンス ジェネレーターを使用するためのベスト プラクティスは何ですか?

4

4 に答える 4

5
  1. はい、あなたの分析は正しいです。あなたは問題を正しく特定しました (同様の問題がありました)。そして...それを本番環境に置く場合は、次のことを忘れないでください。

    • 正しい初期値/初期 ID を使用して、新しいシーケンス ジェネレーターのシーケンス テーブルを手動で生成します (そうしないと、休止状態が 1 から開始され、再び取得されます)
    • またはその値を [コード] に設定します (チェックinitalValueイン@SequenceGenerator)。
  2. ベスト プラクティスを列挙することはできませんが、50 の制限を下げることができると思います。また、PostgreSQL の経験はありませんが、MySQL には seq 用の単純なテーブルがあります。generator と hibernate が全体を作ります。

于 2013-09-25T16:56:50.500 に答える
1

私は同様の問題を抱えていました。私の場合、SQL 経由でデータを直接インポートしました。これにより、「hibernate_sequence」で問題が発生しました。hibernate_sequence は ID 123 でしたが、ID が 123 より大きい行がテーブルにありました。

于 2016-11-08T23:14:27.957 に答える