Hibernate / persistence有哪些常见问题?

时间:2012-07-02 17:47:22

标签: java hibernate testing persistence

我有一个应用程序,我想对可能与Hibernate和/或持久性相关的问题进行测试。

还有什么其他问题?我如何重现它们(字面意思)?你是如何从中恢复过来的?

说清楚:我说的是多线程集群环境(最复杂的环境)。

我的:

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

重现:

  • 加载对象。
  • 使用HQL进行更新。
  • 尝试更新(保存)加载的对象。

处理:不确定......

3 个答案:

答案 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书中所述:

  • 缺少批量更新
  • 缺乏语句缓存
  • 锁定太多
  • 太多的数据库往返
  • 产生低效SQL语句的异国关联