有时,一个从之前的会话中分离的域模型对象需要/可以重新附加而不会触发更新(无论是否有乐观锁)。Hibernate通过提供此功能来支持此类功能
session.lock(myEntity, LockMode.NONE);
因此,Hibernate不会传播修改,除非它们在重新附加到会话之后进行。
不要将其用作优化
首先,尽量避免此功能。通常,使用session.saveOrUpdate()或通过session.get()/session.load()重新附加对象就足够快了。我不是在开玩笑,不要假设在不更新对象(尤其是在启用了版本控制时)或不从数据库检索它的情况下,这会显著更快:在做出任何决定之前进行一些基准测试。
注意边界
相关对象不一定按照您想要的方式管理。未级联的属性不会重新附加到会话。
我目前正在一个项目中工作,该项目中某些实体需要使用无锁模式(NONE)重新附加。在我的情况下,该实体是联系人. 联系人与一些几乎未更新(且已缓存)的实体相关联。在特定但非常常见的情况下,我确信我得到的实例与数据库版本相同。这似乎是使用联系人session.lock(contact, LockMode.NONE);的最佳用例
遗憾的是,我检索到的联系人关联(但未级联)到一些在图形的第二级加载的延迟加载实体,因此我无法正确遍历我的对象图。
我使用的解决方案是通过刷新一些属性以重新定义我的对象图边界。联系人属性。
contact = ... //get it from somewhere session = sf.openSession(); Transaction tx = session.beginTransaction(); ContactType type = session.load( ContactType.class, contact.getContactType().getId() ); contact.setContactType(type); session.lock(contact, LockMode.NONE); //work with contact safely
我现在能够通过联系人遍历我的图形,例如
contact.getContactType().getFavoriteChannel();
注意以下几点
- 我使用了load()而不是get(),这允许我在有代理的情况下获取代理,从而避免访问数据库
- 我在重新附加对象之前设置了刷新属性,以避免不必要的更新。
了解你在做什么
这个功能相当复杂,因为它可能会破坏ACID语义(联系和其他实体没有在同一事务中加载),并且可能会导致非常棘手的问题。我使用了这种优化(减少数据库访问),因为我非常了解我的应用程序的业务流程,我确信它不会破坏任何数据,并且因为它让我节省了大量的时间。我已经认真考虑了以下解决方案。
session.get(Contact.class, contact.getId());
这一行代码是你的朋友,不要过早禁止它。这是与对象交互的最自然方式。