我有一个应用程序,我想对可能与Hibernate和/或持久性相关的问题进行测试。
还有什么其他问题?我如何重现它们(字面意思)?你是如何从中恢复过来的?
说清楚:我说的是多线程集群环境(最复杂的环境)。
我的:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
重现:
处理:不确定......
答案 0 :(得分:7)
延迟加载是您将遇到的一个重大问题,特别是如果您遵循标准的DAO模式。你最终会得到延迟加载的集合,但是当你从DAO层出来时,spring(或者你没有使用spring的话)会关闭会话。
public class MyDaoImpl implements MyDao {
@Override
@Transactional
public void save(MyObject object) { ... }
}
在这种情况下,当对“save”的调用完成时,如果您不在另一个事务中,spring将关闭您的会话。因此,对延迟加载的对象的任何调用都将抛出LazyInitializationException。
处理此问题的典型方法是将会话绑定到当前线程。在webapps中,您可以使用OpenSessionInViewFilter轻松完成此操作。对于命令行,您可能需要编写一个实用程序方法来创建会话,绑定到当前线程,然后在完成后解除绑定。你可以在网上找到这方面的例子。
关于集合的主题,如果你使用“更新”方法(你通常使用标准DAO模式做的事情),你必须小心不要替换集合实例,而是你应该操纵收集已经到位。否则,hibernate将很难确定需要添加/删除/更新的内容。
答案 1 :(得分:2)
您观察到的问题是并发修改数据。 Hibernate有many possible solutions来处理这个问题。
基本上,问题是两个线程(或群集中的两台机器)同时对同一条数据进行操作。考虑这个例子:
machine 1: reads the data and returns it for editing somewhere else
machine 2: also reads the data for modification
machine 1: updates the data and commits.
machine 2: tries to do an update and commit.
第二台机器尝试提交更改时会发生什么?当机器2处理数据时,Hibernate将看到数据已经改变。也就是说,机器2的更新是在陈旧数据上。 Hibernate不能总是合并这两个更改(也不总是期望的行为),所以它通过抛出org.hibernate.StaleObjectStateException
来拒绝第二次更新
正如我上面提到的,Hibernate为您提供了许多解决此问题的方法。最简单的方法是在数据对象上使用@Version
添加版本字段。 Hibernate会自动维护数据的“版本”。每当发生更新时,Hibernate都会自动更改版本。您的工作是检查读取数据与更新数据之间的版本没有变化。如果它们不匹配,您可以做一些事情来处理问题(即告诉用户)。有一些更复杂的技术可以防止并发更新,但这是最简单的。
答案 2 :(得分:1)
获取太多数据可能是您使用ORM工具时可能遇到的最大问题,因为它可以非常轻松地加载超出必要的数据。如果测试数据量相当小,则在开发/测试场景中不会复制此问题,并且一旦数据开始在生产中累积,数据访问层可能会以指数方式变慢。
可能会出现许多问题,如High-Performance Java Persistence书中所述: