6

背景: http://jeffkemponoracle.com/2011/03/11/handling-unique-constraint-violations-by-hibernate

私たちのテーブルは次のとおりです。

BOND_PAYMENTS (BOND_PAYMENT_ID, BOND_NUMBER, PAYMENT_ID)

BOND_PAYMENT_ID には主キー制約があり、(BOND_NUMBER, PAYMENT_ID) には一意の制約があります。

アプリケーションは Hibernate を使用し、ユーザーは特定の債券にリンクされたすべての支払いを表示できます。また、新しいリンクを作成したり、既存のリンクを削除したりできます。ページに必要な変更をすべて加えたら、[保存] をクリックすると、Hibernate が魔法のようにデータベースで必要な SQL を実行します。どうやら、Hibernate はどのレコードを削除する必要があるか、どのレコードを挿入する必要があるかを判断し、残りはそのままにしておきます。残念ながら、最初に INSERT を実行し、次に DELETE を実行します。

ユーザーが支払いへのリンクを削除し、気が変わって同じ支払いへのリンクを再挿入した場合、Hibernate は喜んでリンクを挿入してから削除しようとします。これらの挿入/削除は別個の SQL ステートメントとして実行されるため、Oracle は最初の挿入時にすぐに制約を検証し、ORA-00001 一意の制約違反を発行します。

私たちが知っているのは次の 2 つのオプションだけです。

  1. 制約を延期可能にする
  2. 一意の制約を削除します

オプション 2 はあまり好ましくありません。これは、制約によって、一貫性のないデータが保存される可能性がある厄介なアプリケーションのバグから優れた保護が提供されるためです。オプション1を使用しました。

ALTER TABLE bond_payments ADD
  CONSTRAINT bond_payment_uk UNIQUE (bond_number, payment_id)
  DEFERRABLE INITIALLY DEFERRED;

欠点は、この制約をポリシングするために作成されたインデックスが一意ではないインデックスになったため、クエリの効率が多少低下する可能性があることです。これは、この特定のケースではそれほど大きな不利益ではないと判断しました。もう 1 つの欠点 (Gary のアドバイス) は、特定の Oracle バグに悩まされる可能性があることです。ただし、アプリケーションの動作方法により、(少なくとも、ほとんど) 免疫があると思います。

他に考慮すべきオプションはありますか?

4

1 に答える 1

2

あなたが説明した問題から、エンティティがあるBondPaymentか、またはBondに直接リンクされているかは明確ではありませんPaymentPayment今のところ、とBondを介しての間にリンクがあると思いますBondPayment。この場合、Hibernate は正しいことを行っているため、リンクを取得して削除 (または変更) するロジックをアプリに追加する必要があります。このようなもの:

bond.getBondPayment().setPayment(newPayment);

あなたはおそらく次のようなことをしています:

BondPayment bondPayment = new BondPayment();
bondPayment.setPayment(newPayment);
bondPayment.setBond(bond);
bond.setBondPayment(bondPayment);

最初のケースでは、BondPayment.idが保持され、そのために を変更するだけpaymentです。2 番目のケースでは、それはまったく新しいBondPaymentであり、データベース内の既存のレコードと競合します。

BondPaymentライフサイクルがアプリによって定義されている「通常の」エンティティとして脅威を与えるため、Hibernate は正しいことをしていると言いました。Userこれは、 に一意の制約が設定されているのと同じでありlogin、重複する を含む 2 番目のレコードを挿入しようとしていますlogin。Hibernate は受け入れますが (データベースに が存在するかどうかはわかりませんlogin)、データベースは拒否します。

于 2011-03-11T06:54:06.563 に答える