如何使用Hibernate检测事务冲突?

如何使用Hibernate检测事务冲突?,hibernate,transactions,hibernate-entitymanager,staleobjectstate,Hibernate,Transactions,Hibernate Entitymanager,Staleobjectstate,我正在使用Hibernate 2.6和Hibernate entitymanager。我试图捕捉和处理两个事务在一个对象上发生冲突的情况。发生的情况如下: 两个线程正在更新具有@Version字段的单个对象。释放提交竞争的线程在刷新时记录StaleObjectStateException。不会引发异常,只是记录了异常。我猜事务只有在那一刻才被标记为回滚 之后,当线程尝试执行提交时,它会失败并出现回滚异常。我没有在代码中找到回滚事务的原因 在代码中是否有捕获和处理此类情况的方法?基本上我想捕获St

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

两个线程正在更新具有@Version字段的单个对象。释放提交竞争的线程在刷新时记录StaleObjectStateException。不会引发异常,只是记录了异常。我猜事务只有在那一刻才被标记为回滚

之后,当线程尝试执行提交时,它会失败并出现回滚异常。我没有在代码中找到回滚事务的原因

在代码中是否有捕获和处理此类情况的方法?基本上我想捕获StaleObjectStateException,但问题是-它没有被抛出

更新:我试图从鸟瞰角度完成以下任务:

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

当锁出现问题时,我通常会尝试处理这种情况。我希望在非常高的级别捕获它并显示有效的用户消息(在我的例子中,最高级别是ExceptionMapper for RestEasy)。问题是——当我捕获RollbackException时——已经太晚了

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

看一看。它可以帮助您完成与Nhibernate评测相关的所有工作。

Artem

你能简单地解释一下你想要达到的目标吗?鸟瞰视图,很明显-这是(从)UI代码调用的吗?或者它是服务器端进程(这样您就可以直接控制线程)?我问的原因是,我从这个问题和其他相关问题中得到一种(可能是不正确的)感觉,即您试图使用乐观锁定来实现它不是为之设计的,这就是造成所有问题的原因

StaleObjectStateException
而言,它肯定是从处理显式/隐式刷新的
DefaultFlushEventListener
AutoFlushEventListener
抛出的。您正在手动调用flush()吗?如果不是,则可能是自动刷新(Spring?TransactionManager?EntityManager?)

更新

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

前一种情况可以通过乐观锁定处理;但是,如果没有显式的
flush()
,它将变得不确定(首先进行修改的线程可能不会首先被刷新/提交)。有关更多详细信息,请参阅我对的回答。自动刷新的另一个问题是您当前遇到的问题—在刷新之前不会发现失败的版本检查,并且,如果刷新与提交事务的尝试一致,则引发的异常是回滚异常。无论哪种方式,整个事务都会回滚

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

  • 用户想要编辑实体
  • 检查实体上是否存在锁
  • 是-禁止编辑(允许只读视图?)
  • 否-锁定实体,允许编辑
  • 提交(取消)更改;释放锁
  • 如果使用这种方法,请确保在用户处于某个不活动状态一段时间后使现有锁过期



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

    我使用Hibernate for Java,而不是NHibernate。我想问题不是关于剖析,而是关于异常情况的处理。剖析器将帮助您发现并缩小这些问题的范围。NHProf也支持Hibernate。谢谢。我已经用你询问的信息更新了这个问题。我正在尝试阻止多个线程同时修改。完全防止一个线程覆盖基于旧版本的另一个线程的编辑。你的建议是手动冲洗?只有这样,我才能实现我的目标。考虑一下:线程T1和T2同时读取你的实体,修改它,然后T1保存它,T2保存它。使用自动刷新,您不知道将首先刷新谁的更改(T2或T1)。此外,在刷新更改(和/或根据隔离提交事务)之前,另一个线程甚至不知道对象版本已更改,因此只有在事务失败并回滚时,您才能返回错误。如果您关心变更单或希望尽早获得异常,则必须手动刷新。我已根据您的澄清更新了我的答案