暂时禁用Hibernate实体版本检查

时间:2015-06-15 07:21:23

标签: java hibernate orm persistence jta

我有一个显示所有联系人的页面。这只是一个只读页面,我所做的只是迭代某些组的所有联系人并显示它们:

//Not lazy load of contacts, I cannot use lazy loading
List<Contact> contacts = someService.getContacts(groupId);

for (Contact contact : contacts) {
    //add contact properties to the model to be displayed later
}

同时我可能有一个单独的后台线程来更新其中一个联系人。线程更新了一个我不打算显示的字段,所以在这种情况下,我完全可以使用数据去同步。

问题是Hibernate会更新联系人的版本号并将其提交给我的db(当后台线程完成时)。因此,当我的for循环命中这样的对象时,将抛出以下异常。

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

哪个完全没问题。有没有办法在迭代过程中通过hibernate的集合禁用对象的版本检查?当我说禁用时,我的意思是在这个特殊情况下,在这个特殊的for循环?但不是其他情况。

我认为这是因为底层集合是 AbstractPersistentCollection ,它的迭代器将检查每个成员的版本以及相应的db值。

3 个答案:

答案 0 :(得分:1)

您不能在会话的基础上禁用乐观锁定,但有一些替代方法可以处理这种情况:

  1. 您可以切换到version-less optimistic locking
  2. 您可以将多个Entity片段映射到同一个表,并且您可以拥有一个片段,该片段仅包含特定业务案例所需的列,并且没有版本。这样您就可以绕过常规的Entity乐观锁定检查。

答案 1 :(得分:1)

如果您正在执行只读操作,那么您不应该获得StaleObjectStateException。当您使用过时的数据进行更新并且Hibernate使用版本信息检测到它时,会抛出此异常。

请检查您的代码,确保您没有从显示联系人的只读操作中做任何不必要的更新。

答案 2 :(得分:0)

除了其他答案中描述的解决方案之外,我还可以提出两种解决方案:

  • 在线程中使用原生 sql update 更新 Contact 实体,不要增加版本号。
  • 将更新的字段提取到一个单独的实体中,并且不要在该实体中包含 @Version。在更新 Contacts 的正常事务(由最终用户请求触发)中,使用 OPTIMISTIC_FORCE_INCREMENT 提示。即使您只更新提取的实体,此提示也会强制 Contact 版本号递增。提到的另一个线程可以在没有任何提示的情况下更新提取的实体。

两种解决方案都有缺点,在我看来它们同样丑陋。对于其他答案中提到的解决方案,我也有同样的感觉。我相信 JPA 应该在如何处理乐观版本控制方面提供更大的灵活性。