重新附加未修改的对象

发布者:    |      

有时,一个从之前的会话中分离的域模型对象需要/可以重新附加而不会触发更新(无论是否有乐观锁)。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());

这一行代码是你的朋友,不要过早禁止它。这是与对象交互的最自然方式。


返回顶部