3

私はこの取引をしています:

em.getTransaction().begin();
{
    final Payment payment = em.find(Payment.class, id);
    if (payment.status != Status.INIT)
        throw new IllegalStateException("Cannot set to PAID, is not INIT but " + status);

    payment.status = Status.PAID;

}
em.getTransaction().commit();
log.info("Payment " + id + " was paid");

ただし、ここでわかるように、トランザクションは競合状態を防ぐことはできません。

[11:10:18.265] INFO  [PaymentServlet] [MSP] Status COMPLETED 
[11:10:18.265] INFO  [PaymentServlet] Payment c76f9e75-99d7-4721-a8ac-e3a638dd8317 was paid 
[11:10:18.267] INFO  [PaymentServlet] [MSP] Status COMPLETED 
[11:10:18.267] INFO  [PaymentServlet] Payment c76f9e75-99d7-4721-a8ac-e3a638dd8317 was paid 

支払いはPAID2回に設定されています。私の例外はスローされず、ロールバックなどもありません。

私は何が間違っているのですか?

4

2 に答える 2

7

楽観的ロックを使用する必要があります。オプティミスティック ロックでは、競合する更新がめったに発生しないため、時折トランザクションが発生したときにロールバックしても問題ありません。悲観的ロックにより、データベースは使用中のオブジェクトのロックを保持し、事実上すべてをシングル スレッド化し、パフォーマンスの問題を引き起こす可能性があります。詳細な説明については、http://en.wikibooks.org/wiki/Java_Persistence/Locking#JPA_2.0_Lockingを参照してください。

ここで問題を解決するには、Payment にフィールドを追加し (従来の宣言は非公開の長いバージョンです)、JPA @Version アノテーションを付与する必要があります。スキーマを手動で管理している場合は、対応する列が正しいテーブルに存在することを確認してください。次に、JPA はこのフィールドを使用して競合する更新をチェックし、競合が存在する場合はトランザクションをロールバックします。

更新: 悲観的ロックの詳細: https://blogs.oracle.com/carolmcdonald/entry/jpa_2_0_concurrency_and要するに、オブジェクトをロックするように JPA を構成できますが、そうすることをお勧めすることは非常にまれです。別の言い方をすれば、JDBC へのクエリを手作業でコーディングしている場合、悲観的ロックを発生させるために、各選択の最後に「for update」を記述する必要があります。データベースとデータベースユーザーを泣かせるため、デフォルトでは読み取りをロックしません。

于 2012-05-15T09:27:35.300 に答える
1

使用しているデータベースや、トランザクション分離レベルについては言及していません。SQL 標準に準拠するトランザクションを使用する場合SERIALIZABLE、このエラーは表示されません。9.1 より前のバージョンの PostgreSQL、一部の構成の MS SQL Server、およびすべてのバージョンの Oracle では、要求したときに実際のシリアル化可能なトランザクションが提供されないため、そのような環境では明示的なロックを使用する必要があります。ほとんどのデータベース製品はデフォルトでREAD COMMITTEDトランザクション分離レベルに設定されているため、おそらくトランザクションを明示的に要求する必要がありますSERIALIZABLE

完全な開示、私は MIT の Dan RK Ports と協力して真のシリアライズ可能なトランザクションを PostgreSQL バージョン 9.1 に追加し、Wisconsin Courts ソフトウェアがこれらの問題をきれいに処理できるようにしました。違いの例については、この Wiki ページを参照してください。

于 2012-05-15T12:17:42.340 に答える