0

Java エンティティのコレクションを更新しようとしていますが、Hibernate がバッチ更新を実行する順序により、制約違反の例外が発生します。以下の例を使用して状況を説明します。

エンティティ 学生 Int id 文字列 名前 文字列 デスク ID

ルール: 2 人の生徒が同じ机を持つことはできません

1 回目のトランザクション: 次のように 2 人の生徒を挿入します。 Student 1 Id:1 Name:ABC DeskId:D1

生徒 2 Id:2 名前:DEF DeskId: D2

この後、両方の学生エンティティを更新して机を交換することにし、更新された学生エンティティのコレクションを送信して休止状態にします update Student 1 Id:1 Name:ABC DeskId:D2

生徒 2 Id:2 名前:DEF DeskId: D1

しかし、更新は一度に1レコードずつ行われていると思うので、これは制約違反の例外につながります。

JTA エンティティ マネージャーを使用してトランザクションを管理しています。更新するコードは次のようになります

updateMultiple(Collection<Student> updatedStudents)
        for (final Student student: updatedStudents)
        {
            final Student st= this.entityManager.getReference(Student.class, Student.getId());
            student.merge(st);
        }
        this.entityManager.flush();
        return breakClauseDtos;
4

1 に答える 1

1

問題の原因は明らかです。データベースは、コミット時ではなく、SQL ステートメントの実行時に制約をチェックします。最初の SQL ステートメントを実行すると、制約に違反します。

最初に学生 1 から机を取り外し、それを学生 2 に割り当て、次に学生 1 に自分の机を渡すと、問題を回避できます。これは 3 つの SQL ステートメント (必要以上に 1 つ多い) を意味し、おそらく更新のたびにセッションをフラッシュする必要があります (Hibernate は SQL ステートメントを並べ替えるため、手動の順序に干渉する可能性があります)。

しかし、より良い解決策は、データ モデルの問題を修正することです。

すべての机を 1 人の生徒だけが所有できる場合、机から生徒への関係は 1 です。Desk は学生の ID を外部キーとして必要とします。追加の制約を定義する必要はありません。デスクを変更すると、デスク レコードの学生 ID が変更されます。これは、たった 2 つの update ステートメントで実行できます。

于 2012-10-02T12:08:01.233 に答える