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()
が使われるわけではありません。
期間の長い作業単位の、その他のモデルは、「楽観的同時実行制御」 で述べています。