0

エンティティ User を作成しましたが、整数属性のトランザクション クォータがあります。その値に応じてトランザクション クォータを更新する必要があります。

0 より大きい場合はデクリメントする必要があり、それ以外の場合は値を保持する必要があります。

これが私のアルゴリズムです。

  1. データベースからユーザー エンティティを取得します。
  2. トランザクション クォータを確認し、トランザクション クォータが 0 より大きい場合は、1 減らします。
  3. 変更されたユーザー エンティティを保持します。

上記の場合、2 つのスレッドが同じユーザー エンティティを取得し、両方のスレッドが同じトランザクション クォータ値を読み取り、それが 0 より大きい場合、両方が 1 減らされ、ユーザー エンティティを更新すると、同時要求が発生します。

元。

ThreadA: val = e.getTxnQuota(); val = 5
ThreadB: val = e.getTxnQuota(); val = 5
ThreadA: e.setTxnQuota(val- 1); val = 4 
ThreadB: e.setTxnQuota(val- 1); val =4
ThreadA: eDao.save(e);
ThreadB: eDao.save(e);

上記の場合、保存される値は 3 ではなく 4 です。

では、トランザクション クォータを確認して User エンティティを更新できるアトミック トランザクションを作成する方法はありますか?

4

1 に答える 1

1

これはLockingと呼ばれ、通常は楽観的ロックを使用することをお勧めします。JPAには、それを行うための標準メカニズムが付属しています。バージョン フィールドをエンティティに追加し、@Version で注釈を付けるだけです。

@Version
private long version;

ほら!

ユーザーが保存されるたびに、現在のバージョンがデータベース内のバージョンと比較され、インクリメントされます。

update user set ..., version = version + 1 where id = ... and version = theVersionOfTheUserWhenItWasLoaded

(これはすべて透過的に行われます)。

バージョンが一致しない場合、何も更新されず、JPA エンジンがそれを検出し、OptimisticLockException をスローして、トランザクションにロールバックのマークを付けます。

補足: 上記のシナリオでは、への呼び出しsave()は不要です。添付されたエンティティに加えられたすべての変更は、データベースに自動的に保存されます。エンティティを保存する必要はありません。

于 2012-05-25T17:17:01.080 に答える