0

データベースに永続化された Ticket オブジェクトのキューがあります。キューを含むエンティティは次のようになります。

@Entity
public class StoreQueueCollection {

    @Id
    private int storeId;

    @ManyToMany(fetch=FetchType.LAZY)
    @OrderColumn
    private List<Ticket> mainQueue = new ArrayList<Ticket>();

    @ManyToMany(fetch=FetchType.LAZY)
    @OrderColumn
    private List<Ticket> cancelledQueue = new ArrayList<Ticket>();

    .. etc

あるキューから別のキューにチケットを移動する操作 (これを changeStatus と呼びます) と、新しいチケットをキューの最後に追加する操作 (この newTicket と呼びます) があります。

2 つの操作が同じキューでインターリーブする場合、操作は基本的に機能しますが、キューに「ギャップ」が生じます。データベースでは、これは、0、1、2、4 のように、テーブルの順序列に欠落したインデックスのように見えます。キューが Java にロードされると、欠落したインデックスはキュー内の null 要素になります。

StoreQueueCollection オブジェクトでペシミスティック ロックを使用して、一貫性のないインターリーブ更新を防止していますが、期待どおりに機能していません。追加のログを使用すると、次のような奇妙なシーケンスが表示されます。

- changeTicketStatus() 開始
- entityManager.refresh() を使用してキューをロックします
- キュー A の先頭からチケット X が削除されました
- キューは entityManager.flush()ed です

* newTicket() 開始
* 新しいチケット Y を作成し、entityManager.refresh() を使用して StoreQueueCollection をロックします。
* キュー A の最後にチケット Y が追加されました
* チケット Y には初期化されたフィールドがあり、save()d です
* refresh() を呼び出すと、メソッドがブロックされます

- changeTicketStatus() 再開
    (メモリ内キューを印刷すると、チケット X がキュー A にないことが示されます)
- チケット X が別のキュー B に追加されました
- チケット X の一部のフィールドが変更されました
- チケット X は repository.save() を使用して保存されます
    (メモリ内キューを印刷すると、チケット X がキュー A にないことが示されます)
- changeTicketStatus() 完了

* newTicket() 再開
* refresh() が返す
    (メモリ内キュー A を印刷すると、チケット X がまだキューにあることがわかります!)
* チケット Y はキュー A の最後に追加されます
    (メモリ内キュー A を印刷すると、チケット X と Y がキューにあることがわかります)
* キューは save()d です

すべてのロックは LockModeType.PESSIMISTIC_WRITE であり、スコープは PessimisticLockScope.EXTENDED です。

この一連の実行の後、キュー内の null エントリをチェックする別のスレッドからアサーションがトリガーされます。不思議なことに、行列は基本的に正しい(Xを削除、Yを末尾に追加)のですが、Yの前の注文欄に隙間があります。

私たちが間違っていることについての提案は大歓迎です!

4

1 に答える 1

0

単一の行をロックしていますか、それともすべてのスレッドが共通の「キュー」行をロックしていますか? 後者の場合は、ロックを保持したい間ずっとトランザクションを維持する必要があることに注意してください。前者の場合、単一の (異なる) 行をロックしても、インターリーブ操作を防ぐことはできません。

使用しているバックエンドについては触れていませんが、データベース ロギング ツール (SQL Server のプロファイラーやアクティビティ モニターなど) が、何が起こっているかを判断するのに役立つ場合があります。データベース。

于 2014-11-12T03:14:20.360 に答える