複数トランザクションからDBMSの同一行に対して同時に検索処理から更新処理を実行すると、トランザクション内でデータの一貫性が保たれずにデッドロックなどのエラーが発生する場合があります。
この対策として、Optimistic Locking機能とPessimistic Locking機能が選択できます。
アイソレーションレベル (注) にREAD_COMMITTEDを使用している場合、JPAのOptimistic Locking機能を指定することを推奨します。Optimistic Locking機能は、テーブルの更新時に他トランザクションでレコードに更新がなかったか確認し、更新された場合にはエラーを返却するため、データの一貫性を保ちます。本機能は、行をロックする期間が短いため、同一レコードの更新頻度が少ない高負荷な環境で有効です。
アイソレーションレベル (注) にREAD_COMMITTEDより高いレベル(REPEATABLE_READ、SERIALIZABLE)を使用する場合、Pessimistic Locking機能を指定することを推奨します。Pessimistic Locking機能はデッドロックエラーを防ぐことができる場合があるため、同一のレコードの更新頻度が高い場合に効果的です。
注) アイソレーションレベルの設定については、JDBCドライバのマニュアルを参照してください。
Optimistic Locking機能の定義方法
Optimistic Locking機能はEntityでバージョン番号を意味する列に「@Version」アノテーションを付加することで指定します。
以下はOptimistic Locking機能を指定する方法を示します。
@Version @Column(name = "OPT_LOCK_VER") private int version;
Pessimistic Locking機能の定義方法
Pessimistic Locking機能は、deployment descriptor (orm.xml)のlock-modeタグ、アノテーション(@NamedQueryのlockMode属性)、またはQuery.setLockModeメソッド、EntityManager.findメソッド、EntityManager.lockメソッドで指定します。
以下にアノテーションでPessimistic Locking機能を指定する方法を示します。
@NamedQuery(name="Order.findBigOrders", query="SELECT o FROM Order o WHERE o.quantity > :minimum", lockMode=javax.persistence.LockModeType.PESSIMISTIC_READ)
以下にQuery.setLockModeメソッドを使用し、Pessimistic Locking機能を指定する方法を示します。上記の例との違いは、この指定方法ではこの実行にしか本機能が利用されませんが、上記の指定方法ではOrder.findBigOrdersクエリを使用しているすべての箇所で本機能が利用されることです。
Collection bigOrders = em.createNamedQuery("Order.findBigOrders") .setParameter("minimum", "1000") .setLockMode(javax.persistence.LockModeType.PESSIMISTIC_READ) .getResultList();
注意
行のロック機能に関する注意事項
行のロック機能は、JPQLクエリの機能です。findメソッド、リレーションシップに対するgetアクセッサメソッドなどでは使用できません。
行のロック機能を使用してもDBMSの仕様によりデッドロックが発生する場合があります。この場合には、デッドロックが発生した処理の再実行を試みてください。
データベースが提供するその他のロック機能を使用する場合、NamedQueryアノテーションで定義したJava Persistence Query Language(JPQL)クエリをネイティブSQLのクエリに上書きし、データベースのロック機能を使用するSQLクエリを定義することを検討してください。