1

我正在使用 Hibernate 2.6 和 hibernate-entitymanager。我试图捕捉和处理两个事务在一个对象上发生冲突的情况。这是发生的事情:

两个线程正在更新具有 @Version 字段的单个对象。失去提交竞争的线程在刷新时记录 StaleObjectStateException。异常不会被抛出,它只是被记录。我猜该事务当时被标记为仅回滚。

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

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

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

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

当出现乐观锁问题时,我一般会尝试处理这种情况。我想在非常高的级别捕获它并显示有效的用户消息(在我的情况下,最高级别是 RestEasy 的 ExceptionMapper)。问题是——当我捕捉到 RollbackException 时——已经太晚了。

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

4

2 回答 2

2

阿尔乔姆,

你能简要解释一下你想要达到的目标吗?鸟瞰图,显然 - 就像这是(从)UI 代码调用?或者它是服务器端进程(所以你可以直接控制线程)?我问的原因是我从这个问题和你的其他相关问题中得到一种(也许是不正确的)感觉,即你试图将乐观锁定用于它不是为它设计的东西,这就是造成所有麻烦的原因。

就目前StaleObjectStateException而言,它肯定是从两者中抛出的,DefaultFlushEventListener并且AutoFlushEventListener处理显式/隐式刷新。您是否手动调用 flush() ?如果不是,则异常可能被围绕自动刷新的包装代码捕获/记录(Spring?TransactionManager?EntityManager?)

更新

感谢您澄清问题。我仍然有点不清楚您是要阻止多个线程同时修改1 个同一个实体还是阻止多个用户尝试同时编辑它。

前一种情况可以通过乐观锁来处理;但是,如果没有明确说明flush(),它就会变得不确定(首先进行修改的线程可能不会首先刷新/提交)。有关更多详细信息,请参阅我对这个问题的回答。自动刷新的另一个问题是您当前遇到的问题 - 直到刷新才发现失败的版本检查,如果该刷新与尝试提交事务同时发生,则抛出的异常是 RollbackException。无论哪种方式,整个事务都会回滚。

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

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

如果您采用这种方法,请确保在用户不活动一段时间后使现有锁失效。


在这种情况下,同时修改1并不是很准确(这就是事务的用途);我们正在谈论防止一个线程覆盖基于旧版本的另一个线程的编辑。

于 2009-09-21T18:16:03.163 回答
0

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

于 2009-09-21T11:48:46.227 回答