Java Hibernate/持久化有哪些常见问题?
我有一个应用程序,我想测试与Hibernate和/或持久性相关的可能问题 还有什么问题?我如何复制它们(字面上)?你是如何从中恢复过来的? 明确地说:我说的是多线程集群环境(最复杂的一个) 我的一个:Java Hibernate/持久化有哪些常见问题?,java,hibernate,testing,persistence,Java,Hibernate,Testing,Persistence,我有一个应用程序,我想测试与Hibernate和/或持久性相关的可能问题 还有什么问题?我如何复制它们(字面上)?你是如何从中恢复过来的? 明确地说:我说的是多线程集群环境(最复杂的一个) 我的一个: org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确) 复制: 加载对象 使用HQL更新 尝试更新(保存)加载的对象 句柄:不确定…您观察到的问题是并发修改数据。Hibernate有足够的时间来处理这个问题 本质上,问
org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确)
复制:
- 加载对象
- 使用HQL更新
- 尝试更新(保存)加载的对象
句柄:不确定…您观察到的问题是并发修改数据。Hibernate有足够的时间来处理这个问题 本质上,问题在于两个线程(或集群中的两台机器)同时作用于同一数据段。考虑这个例子:
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.
当第二台机器尝试提交其更改时会发生什么?Hibernate将在计算机2处理数据时看到数据已更改。也就是说,机器2的更新在陈旧数据上。Hibernate不能总是合并这两个更改(也不是总是期望的行为),因此它通过抛出org.Hibernate.StaleObjectStateException
正如我前面提到的,Hibernate为您提供了许多解决此问题的选项。也许最简单的方法是在数据对象上使用
@version
添加一个版本字段。Hibernate将自动维护数据的“版本”。无论何时更新,Hibernate都会自动更改版本。您的工作是检查在读取数据和更新数据之间版本是否没有更改。如果它们不匹配,您可以采取措施处理问题(即告诉用户)。有一些更复杂的技术可以防止并发更新,但这是最简单的。延迟加载是您将遇到的一个大问题,特别是如果您遵循标准DAO模式。您最终将得到延迟加载的集合,但是当从DAO层出来时,spring(或者其他一些东西,如果您不使用spring)可能会关闭会话
public class MyDaoImpl implements MyDao {
@Override
@Transactional
public void save(MyObject object) { ... }
}
在这种情况下,当“save”调用完成时,如果您不在另一个事务中,spring将关闭您的会话。因此,对延迟加载对象的任何调用都将抛出LazyInitializationException
处理此问题的典型方法是将会话绑定到当前线程。在webapps中,您可以使用OpenSessionInViewFilter轻松实现这一点。对于命令行,您可能需要编写一个实用程序方法来创建会话,绑定到当前线程,然后在完成后解除绑定。你可以在网上找到这样的例子
关于集合,如果您使用“更新”方法(这也是您通常使用标准DAO模式所做的),您必须小心不要替换集合实例,而是应该操作已经存在的集合。否则,hibernate将很难找出需要添加/删除/更新的内容。获取太多数据可能是您使用ORM工具时可能遇到的最大问题,因为这样可以很容易地加载超过必要数量的数据。如果测试数据量非常小,并且一旦数据开始在生产中累积,数据访问层就会以指数级的速度变慢,那么这个问题在开发/测试场景中不会重现 可能会出现许多问题:
- 缺少批更新
- 缺少语句缓存
- 锁得太多
- 数据库往返次数过多
- 生成低效SQL语句的奇异关联