2012-11-27 33 views
17

JPAとロック・モードについてのOracle hereのブログで記事を読んでいます。JPAとオプティミスティック・ロック・モード

ロックモードタイプのOPTIMISTICOPTIMISTIC_FORCE_INCREMENTの違いはよくわかりません。

OPTIMISTICモード:ユーザーはこのモードを持つエンティティをロックすると

enter image description here

、チェックがトランザクションの開始とバージョンのチェックイン時にバージョンフィールドのエンティティ(@version)上で行われますフィールドはトランザクションの終了時にも行われます。バージョンが異なる場合、トランザクションはロールバックされます。

OPTIMISTIC_FORCE_INCREMENTモード:

enter image description here

ユーザーはこのモードを選択すると、彼は手動でバージョンフィールドをインクリメントするために、データベースへのEntityManagerの()状態をフラッシュする必要があります。したがって、他のすべての最適化トランザクションは無効になります(ロールバック)。トランザクションのコミットまたはロールバックのために、トランザクションの終了時にバージョンのチェックも行われます。

私はOPTIMISTICまたはOPTIMISTIC_FORCE_INCREMENTモードをいつ使うべきですか?私が見ている唯一の基準は、トランザクションが実行中の他のすべてのトランザクションをロールバックするため(他のトランザクションよりも優先順位が高い)、OPTIMISTIC_FORCE_INCREMENTモードを適用することです。

OPTIMISTICモードではなく、このモードを選択する別の理由がありますか?

ありがとうございました

+0

フィールド(@oneToOne、@oneToMany)として別のタイプのエンティティを含むエンティティを更新する場合は、OPTIMISTIC_FORCE_INCREMENTを使用します。したがって、リストを更新する場合は、OPTIMISTIC_FORCE_INCREMENT(たとえば、すべてのListItem)でロックします。したがって、コミットするときに、更新したいエンティティにリンクされているすべてのエンティティが変更されていないことを確認します。ではない ? –

答えて

10

通常、あなたは楽観的なロックのためにlock()APIを使用しません。 JPAは、更新または削除のバージョン列を自動的にチェックします。

オプティミスティックロックのlock()APIの唯一の目的は、更新が変更/更新されていない別のオブジェクトに依存している場合です。これにより、他のオブジェクトが変更された場合でもトランザクションは失敗します。

これを行うタイミングは、アプリケーションとユースケースによって異なります。 OPTIMISTICはコミット時に他のオブジェクトが更新されていないことを保証します。 OPTIMISTIC_FORCE_INCREMENTは、他のオブジェクトが更新されていないことを保証し、コミット時にそのバージョンをインクリメントします。

オプティミスティックロックはコミット時に常に検証され、コミットするまで成功する保証はありません。 flush()を使用すると、事前にデータベースを強制的にロックしたり、以前のエラーをトリガーしたりすることができます。

+0

NONE(私が思うデフォルトモード)とOPTIMISTICの違いは何ですか? Thx –

+0

flush()は、コミット前のバージョンを他のトランザクションから見えるようにインクリメントすることが保証されていますか? – Catweazle

38

この長い答えで怖がらないでください。このトピックは単純ではありません。あなたが任意のロック(LockModeType.NONEを使用するのと同じ動作)を指定しない場合、デフォルトJPAことで

読むを課すは分離レベルを犯しました。

読むには汚れの非存在現象を読んで必要と約束しました。単にT1は、T2がコミットした後にT2によって行われた変更を見ることができます。

JPAでのオプティミスティック・ロックの使用は、隔離レベルを に変更します。反復可能な読み取りは、です。

トランザクションの開始時と終了時にT1が一部のデータを読み取る場合、の反復可能な読み取りは、T2がデータを変更してT1の途中でコミットした場合でも同じデータを表示します。

ここではトリッキーな部分があります。 JPAはを実現します。を可能な限り単純に読み取ることができます。防止Non-Repetable read現象。 JPAはあなたの読書のスナップショットを保持するのに十分な洗練されたものではありません。これは単に、例外を発生させることによって(データが最初の読み込みから変更された場合)、2回目の読み込みを防止します。

次の2つの楽観的ロックのオプションから選択できます

:違いは何

  • LockModeType.OPTIMISTIC(JPA 1.0でLockModeType.READ

  • LockModeType.OPTIMISTIC_FORCE_INCREMENT(JPA 1.0でLockModeType.WRITE

ふたつの間に?

このPersonエンティティの例を説明しましょう。

@Entity 
public class Person { 
    @Id int id; 
    @Version int version; 
    String name; 
    String label; 
    @OneToMany(mappedBy = "person", fetch = FetchType.EAGER) 
    List<Car> cars; 
    // getters & setters 
} 

今、私たちは、データベースに格納されジョンという名前の1人を持っていると仮定しましょう。私たちはこの人をT1で読むが、彼の名前はマイクに2番目のトランザクションT2で変更する。変更が他のエンティティ(おそらく非所有関係)に言及する場合、任意のロック

Person person1 = em1.find(Person.class, id, LockModeType.NONE); //T1 reads Person("John") 

Person person2 = em2.find(Person.class, id); //T2 reads Person("John") 
person2.setName("Mike"); //Changing name to "Mike" within T2 
em2.getTransaction().commit(); // T2 commits 

System.out.println(em1.find(Person.class, id).getName()); // prints "John" - entity is already in Persistence cache 
System.out.println(
    em1.createQuery("SELECT count(p) From Person p where p.name='John'") 
    .getSingleResult()); // prints 0 - ups! don't know about any John (Non-repetable read) 

楽観的読み取りロック

Person person1 = em1.find(Person.class, id, LockModeType.OPTIMISTIC); //T1 reads Person("John") 

    Person person2 = em2.find(Person.class, id); //T2 reads Person("John") 
    person2.setName("Mike"); //Changing name to "Mike" within T2 
    em2.getTransaction().commit(); // T2 commits 

    System.out.println(
      em1.createQuery("SELECT count(p) From Person p where p.name='John'") 
        .getSingleResult()); // OptimisticLockException - The object [[email protected]] cannot be updated because it has changed or been deleted since it was last read. 


LockModeType.OPTIMISTIC_FORCE_INCREMENTなし

が使用され、我々は完全性を維持したい。 ジョンが新しい車を買収したことを説明しましょう。

楽観読み取りロック

Person john1 = em1.find(Person.class, id); //T1 reads Person("John") 

Person john2 = em2.find(Person.class, id, LockModeType.OPTIMISTIC); //T2 reads Person("John") 
//John gets a mercedes 
Car mercedes = new Car(); 
mercedes.setPerson(john2); 
em2.persist(mercedes); 
john2.getCars().add(mercedes); 
em2.getTransaction().commit(); // T2 commits 

//T1 doesn't know about John's new car. john1 in stale state. We'll end up with wrong info about John. 
if (john1.getCars().size() > 0) { 
    john1.setLabel("John has a car"); 
} else { 
    john1.setLabel("John doesn't have a car"); 
} 
em1.flush(); 

楽観書き込みロック

Person john1 = em1.find(Person.class, id); //T1 reads Person("John") 
Person john2 = em2.find(Person.class, id, LockModeType.OPTIMISTIC_FORCE_INCREMENT); //T2 reads Person("John") 
//John gets a mercedes 
Car mercedes = new Car(); 
mercedes.setPerson(john2); 
em2.persist(mercedes); 
john2.getCars().add(mercedes); 
em2.getTransaction().commit(); // T2 commits 

//T1 doesn't know about John's new car. john1 in stale state. That's ok though because proper locking won't let us save wrong information about John. 
if (john1.getCars().size() > 0) { 
    john1.setLabel("John has a car"); 
} else { 
    john1.setLabel("John doesn't have a car"); 
} 
em1.flush(); // OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) 

JPAの仕様では、以下の発言があるが、HibernateとEclipseLinkのはうまく動作し、それを使用しないでください。実装はLockModeType.OPTIMISTICはなく、その逆、 を要求されたLockMode- Type.OPTIMISTIC_FORCE_INCREMENTを使用するバージョンのオブジェクトについて

は、それが許容されます。

+0

最後の例では、ロックが使用されていないためem1.flush()を実行すると、例外が発生してはいけません。実際にあなたのエンティティでバージョンを使用したため、http://stackoverflow.com/a/19872657/1059372 – Eugene

+0

私はHibernate 4.3.6.FinalとEclipselink 2.5.1に対して私のサンプルをテストしました。あなたの懸念について:Hibernateメッセージはコメントに表示されます。 Eclipselinkは* OptimisticLockExceptionを出力します。[Person @ 716d7daf]オブジェクトは、最後に読み込まれてから変更または削除されたため、更新できません。 – zbig

+0

'@ Vesion'カラムが' Person'になくても動作するかどうかを調べたところ、ロック時に失敗しました。 * AssertionFailureによるHibernate:バージョン管理されていないエンティティではバージョン増分を強制できません* PersistenceExceptionでEclipselink:バージョンロックインデックスを持たないエンティティに対して無効なロックモードタイプがオンになっています。 * – zbig

0

としては、あなたがbetter off coupling it with a PESSIMISTIC_READ or PESSIMISTIC_WRITEをしているのでthis postで、LockModeType.OPTIMICTICチェックイン-行為の問題に苦しんで説明しました。

一方、LockModeType.OPTIMICTIC_FORCE_INCREMENTは、データの不一致の問題がありません。通常、子エンティティが変更されるたびに親エンティティのバージョンを制御するために使用します。

LockModeType.OPTIMICTIC_FORCE_INCREMENTまたはLockModeType.PESSIMISTIC_FORCE_INCREMENTを使用する方法の詳細については、this articleを参照してください。親エンティティのバージョンでは、子エンティティの変更も同様に考慮する必要があります。

関連する問題