6

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

还有什么问题?我如何复制它们(字面意思)?你如何从他们身上恢复过来?

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

我的唯一:

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

复制:

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

手柄:不确定...

4

3 回答 3

8

延迟加载是您将遇到的大问题之一,特别是如果您遵循标准 DAO 模式。你最终会得到延迟加载的集合,但是从你的 DAO 层出来后,spring (或者如果你不使用 spring 的话)可能会关闭会话。

public class MyDaoImpl implements MyDao {
   @Override
   @Transactional
   public void save(MyObject object) { ... }
}

在这种情况下,当“保存”调用完成时,如果您不在另一个事务中,spring 将关闭您的会话。因此,任何对延迟加载对象的调用都将引发 LazyInitializationException。

处理此问题的典型方法是将会话绑定到当前线程。在 webapps 中,您可以使用 OpenSessionInViewFilter 轻松完成此操作。对于命令行,您可能需要编写一个实用方法来创建会话,绑定到当前线程,然后在完成后取消绑定。你可以在网上找到这方面的例子。

关于集合的主题,如果您使用“更新”方法(同样是您通常使用标准 DAO 模式执行的操作),您必须小心不要替换集合实例,而是应该操作已经存在的集合到位。否则,休眠将很难确定需要添加/删除/更新的内容。

于 2012-07-02T18:17:03.927 回答
2

您观察到的问题是数据的并发修改之一。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.

当第二台机器尝试提交其更改时会发生什么?当机器 2 处理数据时,Hibernate 将看到数据已更改。也就是说,机器 2 的更新是在stale data上。Hibernate 不能总是合并这两个更改(也不是总是需要的行为),所以它通过抛出来拒绝第二次更新org.hibernate.StaleObjectStateException

正如我上面提到的,Hibernate 为您提供了许多解决此问题的选项。@Version最简单的可能是在您的数据对象上添加一个版本字段。Hibernate 会自动维护数据的“版本”。每当发生更新时,Hibernate 会自动更改版本。您的工作是检查在读取数据和更新数据之间版本没有发生变化。如果它们不匹配,您可以采取一些措施来处理问题(即告诉用户)。有一些更复杂的技术可以防止并发更新,但这是最简单的。

于 2012-07-02T17:53:48.143 回答
1

当您使用 ORM 工具时,获取过多数据可能是您可能遇到的最大问题,因为它可以很容易地加载比需要更多的数据。如果测试数据量相当小,这个问题在开发/测试场景中不会复制,并且一旦数据开始在生产中积累,数据访问层就会成倍地变慢。

可能会出现很多问题:

  • 缺少批量更新
  • 缺少语句缓存
  • 锁定过多
  • 数据库往返次数过多
  • 生成低效 SQL 语句的奇异关联
于 2016-04-06T10:06:53.137 回答