10.6. 修改脱管(Detached)对象

优质
小牛编辑
132浏览
2023-12-01

很多程序需要在某个事务中获取对象,然后将对象发送到界面层去操作,最后在一个新的事务保存所做的修改。在高并发访问的环境中使用这种方式,通常使用附带版本信息的数据来保证这些“长“工作单元之间的隔离。

Hibernate 通过提供 Session.update()Session.merge() 重新关联脱管实例的办法来支持这种模型。

// 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 之前已经被另一Session(secondSession)装载了, 应用程序进行重关联操作(reattach)的时候会抛出一个异常。

如果你确定当前 session 没有包含与之具有相同持久化标识的持久实例,使用 update()。如果想随时合并你的的改动而不考虑 session 的状态,使用 merge()。换句话说,在一个新 session 中通常第一个调用的是 update() 方法,以便保证重新关联脱管(detached)对象的操作首先被执行。

The application should individually update() detached instances that are reachable from the given detached instance only if it wants their state to be updated. This can be automated using transitive persistence. See 第 10.11 节 “传播性持久化(transitive persistence)” for more information.

lock() 方法也允许程序重新关联某个对象到一个新 session 上。不过,该脱管(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 文档以及关于事务处理(transaction handling)的章节。重新关联不是 lock() 的唯一用途。

Other models for long units of work are discussed in 第 12.3 节 “乐观并发控制(Optimistic concurrency control)”.