10.6. 分離オブジェクトの修正

多くのアプリケーションでは、あるトランザクションでオブジェクトを復元し、操作するためにオブジェクトを UI 層に送り、その後に、新しいトランザクションで変更を保存する必要があります。並行性の高い環境で、このタイプのアプローチを使うアプリケーションでは通常、「期間の長い」作業単位の隔離性を保証するために、バージョンデータが使われます。
Hibernate は、Session.update()Session.merge() メソッドを使って、detached インスタンスを再追加することで、このモデルに対応します。
// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);

// in a higher layer of the application
cat.setMate(potentialMate);

// later, in a new session
secondSession.update(cat);  // update cat
secondSession.update(mate); // update mate
識別子 catId を持つ Cat が、既に secondSession でロードされていた場合は、再追加しようとしたときに、例外が投げられます。
同じ識別子を持つ永続インスタンスをセッションが既に保持していないことを確信できる場合は update() を使います。そして、セッションの状態を考えずに、いつでも変更をマージしたい場合は、merge() を使います。すなわち、detached インスタンスの再追加操作が、最初に確実に実行されるようにするには、通常は update() が新しいセッションのなかで最初に呼ばれるメソッドになります。
その状態を更新したい場合に 限り、このdetached インスタンスから到達可能な、detached インスタンスをアプリケーションは個別に update() すべきです。遷移的な永続化 を使えば、もちろん自動化できます。「連鎖的な永続化」を参照してください。
lock() メソッドでもまた、新しいセッションにオブジェクトを再関連付けできます。しかし、detached インスタンスは無修正でなければなりません。
//just reassociate:
sess.lock(fritz, LockMode.NONE);
//do a version check, then reassociate:
sess.lock(izi, LockMode.READ);
//do a version check, using SELECT ... FOR UPDATE, then reassociate:
sess.lock(pk, LockMode.UPGRADE);
lock() は、さまざまな LockMode とともに使うことができる点に注意してください。詳細は、 API ドキュメントとトランザクション処理の章を参照してください。再追加のときにだけ、 lock() が使われるわけではありません。
期間の長い作業単位の、その他のモデルは、「楽観的同時実行制御」 で述べています。