Spring Data JPAでトランザクションロックを有効にする

1. 概要

このクイックチュートリアルでは、https://www.baeldung.com/spring-data-jpa-query [カスタムクエリメソッド]および事前定義されたリポジトリCRUDメソッドに対して、Spring Data JPAでトランザクションロックを有効にする方法について説明します。
また、さまざまなロックタイプとトランザクションロックタイムアウトの設定についても説明します。

2. ロックの種類

JPAには、悲観的ロックと楽観的ロックの2つの主要なロックタイプが定義されています。

2.1悲観的ロック

*トランザクションでlink:/jpa-pessimistic-locking[Pessimistic Locking]を使用し、エンティティにアクセスすると、すぐにロックされます*。 トランザクションは、トランザクションをコミットまたはロールバックすることによりロックを解除します。

2.2楽観的ロック

  • https://www.baeldung.com/jpa-optimistic-locking [Optimistic Locking]では、トランザクションはエンティティをすぐにロックしません。*代わりに、トランザクションは通常、エンティティに割り当てられたバージョン番号で状態を保存します。

    別のトランザクションでエンティティの状態を更新しようとすると、トランザクションは更新中に保存されたバージョン番号と既存のバージョン番号を比較します。
    この時点で、バージョン番号が異なる場合、エンティティを変更できないことを意味します。 アクティブなトランザクションがある場合、そのトランザクションはロールバックされ、基盤となるJPA実装は_https://docs.oracle.com/javaee/7/api/javax/persistence/OptimisticLockException.html [OptimisticLockException] ._をスローします。
    バージョン番号のアプローチとは別に、現在の開発コンテキストに最も適しているアプローチに応じて、タイムスタンプ、ハッシュ値の計算、シリアル化されたチェックサムなどの他のアプローチを使用できます。

3. クエリメソッドでトランザクションロックを有効にする

**エンティティのロックを取得するには、ターゲットクエリメソッドに_https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repositoryで注釈を付けることができます。 /Lock.html[Lock]_注釈。必要なロックモードタイプを渡します** __.__
https://docs.oracle.com/javaee/7/api/javax/persistence/LockModeType.html [ロックモードタイプ]は、エンティティのロック中に指定する列挙値です。 次に、指定されたロックモードがデータベースに伝達され、エンティティオブジェクトに対応するロックが適用されます。
Spring Data JPAリポジトリのカスタムクエリメソッドでロックを指定するには、メソッドに_ @ Lock_アノテーションを付け、必要なロックモードタイプを指定します。
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
@Query("SELECT c FROM Customer c WHERE c.orgId = ?1")
public List<Customer> fetchCustomersByOrgId(Long orgId);
_findAll_や_findById(id)_などの事前定義されたリポジトリメソッドにロックを強制するには、リポジトリ内でメソッドを宣言し、_Lock_アノテーションでメソッドに注釈を付ける必要があります。
@Lock(LockModeType.PESSIMISTIC_READ)
public Optional<Customer> findById(Long customerId);
ロックが明示的に有効化され、アクティブなトランザクションがない場合、基盤となるJPA実装は_https://docs.oracle.com/javaee/7/api/javax/persistence/TransactionRequiredException.html [TransactionRequiredException] _をスローします。
ロックを許可できず、ロックの競合によってトランザクションがロールバックされない場合、JPAはhttps://docs.oracle.com/javaee/7/api/javax/persistence/LockTimeoutException.html[_LockTimeoutException_]をスローします。 ただし、アクティブなトランザクションにロールバックのマークを付けません。

4. トランザクションロックタイムアウトの設定

悲観的ロックを使用すると、データベースはすぐにエンティティをロックしようとします。 ロックをすぐに取得できない場合、基礎となるJPA実装は_LockTimeoutException_をスローします。 このような例外を回避するために、ロックタイムアウト値を指定できます。
Spring Data JPAでは、https://docs.spring.io/spring-data/jpa/docs/current/api/index.html?org / springframework / data / jpa / repository / QueryHintsを使用してロックタイムアウトを指定できます。クエリメソッドにhttps://docs.oracle.com/javaee/7/api/javax/persistence/QueryHint.html[_QueryHint_]を配置することによる.html [_QueryHints_]アノテーション:
@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);
さまざまなスコープでのロックタイムアウトヒントの設定の詳細については、このhttps://www.objectdb.com/java/jpa/persistence/lock#Pessimistic_Locking_[ObjectDBの記事]を参照してください。

5. 結論

このチュートリアルでは、さまざまなタイプのトランザクションロックモードを学習しました。 Spring Data JPAでトランザクションロックを有効にする方法を学びました。 また、ロックタイムアウトの設定についても説明しました。
適切な場所に適切なトランザクションロックを適用すると、大量の同時使用アプリケーションでデータの整合性を維持できます。
*トランザクションがACIDルールを厳密に遵守する必要がある場合、ペシミスティックロックを使用する必要があります。 オプティミスティックロックは、複数の同時読み取りを許可する必要がある場合、およびアプリケーションコンテキスト内で結果整合性が許容される場合に適用する必要があります。*
もちろん、悲観的ロックと楽観的ロックの両方のサンプルコードは、https://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5 [Githubで]にあります。