2011-07-14 7 views
5

私のWebアプリケーションでは、Hibernateでオプティミスティック(バージョニング)とペシミスティックロックを実装することに決めた理由で、同じデータに同時にアクセスするスレッドがいくつかあります。時々私はStaleObjectException取得しています、しかしエンティティを正しくロックしてリロードする方法

@Transactional 
public void doSomething(entity) { 
    session.lock(entity, LockMode.UPGRADE); 
    session.refresh(entity); 

    // I change the entity itself as well as entites in a relationship. 
    entity.setBar(...); 
    for(Child childEntity : entity.getChildren()) { 
     childEntity.setFoo(...); 
    } 
} 

@:

は現在、私は、エンティティをロックし、(@Transactionalとスプリングストランザクションマネージャとトランザクション区分を使用して)、その上に書き込み操作を実行するには、次のパターンを使用しますTransactionalは、ChildEntityが同時に変更され、間違ったバージョンを持つことを示すフラッシングです。

entityとその子どもたちが正しくリフレッシュされていないと思いますので、古いデータで作業しています。誰かがこれを達成する方法を指摘できますか?私のいくつかの考えには、永続コンテキスト(セッション)をクリアするか、session.lock(entity, LockMode.READ)を再度呼び出すことが含まれていましたが、ここで何が正しいかわかりません。

ありがとうございました!

答えて

0

「LockMode.UPGRADE」と楽観的ロックを共存させる理由を教えてください。論争のようなもののように見える。

Hibernateはオブジェクトをメモリにロックせず、常にデータベースのロック機構を使用します。また、 "要求されたロックモードがデータベースでサポートされていない場合、Hibernateは例外をスローするのではなく適切な代替モードを使用します。つまり、データベースがSELECT ... FOR UPDATEをサポートしていない場合は、おそらくこれらの例外が発生します。

もう1つの理由は、子供に「org.hibernate.annotations.CascadeType.LOCK」を使用していない可能性があります。

+0

"SELECT ... FOR UPDATE"をサポートするMySQL InnoDBを使用していますので、ここでは問題はありません。さらに、同時に変更が行われたときに「通知」を得るために、私はオプティミスティック・ロックも使用しています。 – Erik

+0

申し訳ありませんが、あなたが子供に問題があるという点を忘れています(これは太字です:)。私は答えを更新しました... – Stas

+0

私のコードでは、エンティティを常にロックしますが、エンティティを更新するのは子供だけではありません。したがって、ロックが取得される必要があります。私の主な関心事は、リフレッシュだけを使って最新のエンティティ/子どもたちと一緒に作業していないということです。 – Erik

1

このHibernate-Issue:LockMode.Upgrade doesn't refresh entity valuesを参照してください。

要約:Hibernatは、指定されたエンティティがすでにプリロードされている場合、成功したロックの後に選択を実行しません。ロックを受け取った後、エンティティのためにリフレッシュを呼び出す必要があります。

関連する問題