1

我使用hibernate 2.6与hibernate-entitymanager。我试图捕捉并处理2个事务在对象上发生冲突时的情况。这里是发生了什么:如何检测与Hibernate的事务冲突?

两个线程正在更新一个单一的对象,至少有@Version字段。在刷新时丢失提交竞赛的线程记录StaleObjectStateException。该异常不会被抛出,它只是被记录下来。我猜这个交易标记为回滚 - 仅在那一刻。

之后,当线程尝试执行提交时,它会失败并显示RollbackException。我没有找到一种方法在代码中找出事务回滚的原因。

有没有办法在代码中捕获和处理这种情况?基本上我想捕获StaleObjectStateException,但问题是 - 它不会抛出。

更新:我试图从鸟瞰完成的事情是:

我的JBoss下运行的J2EE应用程序。它有一些内部的定时器调用服务和从UI调用的服务。它也有一个关键实体。我需要确保不同的线程不能同时更新该实体类的对象,因为它可能导致数据不一致。这就是我实施乐观锁定的原因。

当发生乐观锁问题时,我试图通常处理这种情况。我想在非常高的层次上捕获它并显示有效的用户消息(在我的情况下,最高级别是RestEasy的ExceptionMapper)。问题是 - 当我收到RollbackException时 - 已经太晚了。

我不会手动冲洗。我的大多数EJB使用CMT,会话自动刷新。

+0

我已根据您的说明更新了我的答案 – ChssPly76 2009-09-22 21:19:16

回答

0

看看NHProf。它可以帮助你处理与Nhibernate分析有关的所有事情。

+0

我使用Hibernate for Java,而不是NHibernate。我的问题不是关于性能分析,而是关于处理 – artemb 2009-09-21 11:59:01

+0

的异常情况,它将帮助您检测这些问题并缩小范围。 NHProf - 支持Hibernate。 – 2009-09-21 15:40:36

2

Artem,

你能简单解释一下你想达到的目标吗?显然,鸟瞰图就像这样(从UI代码中调用)?或者它是服务器端的过程(所以你可以直接控制线程)?我问的原因是,我得到了一个(也许是不正确的)感觉,以及你尝试使用乐观锁定的其他相关问题,而这些问题并不是针对这些问题设计的,这就是所有的问题。

只要StaleObjectStateException去,它是最明显抛出DefaultFlushEventListenerAutoFlushEventListener处理显式/隐式刷新。你是否手动调用flush()?通过围绕汽车冲洗包装代码如果不是这样,也许被捕获的异常/登录(春?事务管理?EntityManager的?)

更新

感谢您澄清这个问题。我还是有点不清楚是否要防止多线程同时修改 相同的实体或预防多发性用户从试图同时编辑。

以前的方案可以通过乐观锁定来处理;然而,如果没有明确的flush()它变得非确定性(线程,使修改首先可能不会被刷新/提交第一)。有关更多详细信息,请参阅我对this question的回答。自动刷新的另一个问题是您目前遇到的问题 - 直到刷新才发现失败的版本检查,如果该刷新与尝试提交事务一致,抛出的异常是RollbackException。无论哪种方式,整个事务都会回滚。

后一种情况(阻止用户编辑)不能通过乐观锁定来处理。您需要实施悲观锁定 - 而不是在数据库或应用程序级别。换句话说,其过程是:

  1. 用户想如果实体
  2. 是存在锁定编辑实体
  3. 检查 - 禁止编辑(允许只读视图?)
  4. NO - 锁实体,允许编辑
  5. 提交(取消)更改;释放锁

如果使用此方法,请务必在用户不活动的一段时间后过期锁定现有锁。


同时修改 是不是在这种情况下,真正准确的(这就是交易的);我们正在讨论防止一个线程覆盖基于旧版本的另一个线程的编辑。

+0

谢谢。我已经用你问的信息更新了这个问题。 – artemb 2009-09-22 06:53:23

+0

我想阻止多个线程同时修改。完全防止一个线程覆盖基于旧版本的另一个线程的编辑。 那么你的建议是手动冲洗?只有这样我才能实现我的目标? – artemb 2009-09-23 07:30:32

+0

考虑一下:线程T1和T2同时读取您的实体,修改它,然后T1保存它,T2保存它。使用自动刷新功能,您不知道哪些更改(T2或T1)将首先被刷新。此外,直到更改刷新(和/或事务提交取决于隔离),另一个线程甚至不会知道对象版本已更改,因此只有在事务失败并正在回滚时才会返回错误。如果您关心更改订单或想要尽早获得例外,则必须手动清空。 – ChssPly76 2009-09-23 16:17:08