Hibernate / persistence有哪些常见问题?

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

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

为了说清楚:我在谈论multithreading集群环境(最复杂的环境)。

我的唯一:

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

复制:

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

处理:不确定……

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

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

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

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

关于集合的主题,如果你使用“更新”方法(你通常使用标准DAO模式做的事情),你必须小心不要替换集合实例,而是你应该操纵已经集合的到位。 否则,hibernate将很难确定需要添加/删除/更新的内容。

您观察到的问题是并发修改数据之一。 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的更新是关于过时的数据 。 Hibernate不能总是合并这两个更改(也不是总是需要的行为),所以它通过抛出org.hibernate.StaleObjectStateException来拒绝第二次更新

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

获取太多数据可能是您使用ORM工具时可能遇到的最大问题,因为它可以非常轻松地加载超出必要的数据。 如果测试数据量相当小,则在dev /测试场景中不会复制此问题,并且一旦数据开始在生产中累积,数据访问层可能会以指数方式变慢。

可能会出现许多问题,如“ 高性能Java持久性”一书中所述:

  • 缺乏批量更新
  • 缺乏语句缓存
  • 锁定太多了
  • 太多的数据库往返
  • 生成效率低下的SQL语句的exception关联