我有一个显示所有联系人的页面。这只是一个只读页面,我所做的只是迭代某些组的所有联系人并显示它们:
//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值。
答案 0 :(得分:1)
您不能在会话的基础上禁用乐观锁定,但有一些替代方法可以处理这种情况:
答案 1 :(得分:1)
如果您正在执行只读操作,那么您不应该获得StaleObjectStateException。当您使用过时的数据进行更新并且Hibernate使用版本信息检测到它时,会抛出此异常。
请检查您的代码,确保您没有从显示联系人的只读操作中做任何不必要的更新。
答案 2 :(得分:0)
除了其他答案中描述的解决方案之外,我还可以提出两种解决方案:
Contact
实体,不要增加版本号。Contacts
的正常事务(由最终用户请求触发)中,使用 OPTIMISTIC_FORCE_INCREMENT
提示。即使您只更新提取的实体,此提示也会强制 Contact
版本号递增。提到的另一个线程可以在没有任何提示的情况下更新提取的实体。两种解决方案都有缺点,在我看来它们同样丑陋。对于其他答案中提到的解决方案,我也有同样的感觉。我相信 JPA 应该在如何处理乐观版本控制方面提供更大的灵活性。