如何检测与Hibernate的事务冲突?

发布于 2024-08-04 21:15:47 字数 693 浏览 3 评论 0原文

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

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

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

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

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

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

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

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

I am using Hibernate 2.6 with hibernate-entitymanager. I am trying to catch and handle situations when 2 transactions conflict on an object. Here is what happens:

Two threads are updating a single object wich has a @Version field. The thread which looses commit race logs StaleObjectStateException on flush. The exception is not thrown, it is just logged. I guess the transaction is marked rollback-only at that moment.

After that when the thread tries to perform commit it fails with RollbackException. I did not find a way to find out in the code why the transaction is rolled back.

Is there a way to catch and handle such situations in the code? Basicly I want to catch StaleObjectStateException, but the problem is - it is not thrown.

UPDATE: The thing I am trying to accomplish from the birds eye view is the following:

I have a J2EE app running under JBoss. It has some internal timer-invoked services and the ones invoked from the UI. It also has one critical entity. I need to ensure that different threads can not update objects of that entity class simultaniously because it may result in data inconsistency. This is why I am implementing optimistic locking.

When an optimistick lock problem occurs I am trying to handle this situation generally. I want to catch it at the very high level and show a valid user message (in my case the highest level is ExceptionMapper for RestEasy). The problem is - when I catch RollbackException - it is already too late.

I do not flush manually. Most of my EJBs use CMT and the sessions are flushed automatically.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

丿*梦醉红颜 2024-08-11 21:15:47

Artem,

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

StaleObjectStateException 而言,它肯定是从处理显式/隐式刷新的 DefaultFlushEventListenerAutoFlushEventListener 抛出的。您是否手动调用flush()?如果没有,可能异常是由自动刷新周围的包装器代码捕获/记录的(Spring?TransactionManager?EntityManager?)

更新

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

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

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

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

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


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

Artem,

Can you briefly explain what is it you're trying to achieve? Bird's eye view, obviously - like is this (invoked from) UI code? Or is it server-side process (so you'd have direct controls over threads)? The reason I ask is I get a (perhaps incorrect) feeling from this and your other related questions that you're trying to use optimistic locking for something it wasn't designed for and that's what's causing all the trouble.

As far as StaleObjectStateException goes, it is most definitely thrown from both DefaultFlushEventListener and AutoFlushEventListener that handle explicit / implicit flushes. Are you invoking flush() manually? If not, perhaps the exception is being caught / logged by wrapper code around auto flushing (Spring? TransactionManager? EntityManager?)

Update

Thank you for clarifying the question. I'm still a bit unclear about whether you want to prevent multiple threads from concurrently modifying1 the same entity or prevent multiple users from trying to concurrently edit it.

Former scenario can be handled via optimistic locking; however without explicit flush() it becomes non-deterministic (thread that made the modification first may not be flushed / committed first). See my answer to this question for more details. Another problem with automatic flush is what you're currently experiencing - failed version check is not discovered until flush and, if that flush coincides with attempt to commit transaction, exception thrown is RollbackException. Either way, entire transaction is rolled back.

Latter scenario (preventing users from editing) can NOT be handled by optimistic locking. You will need to implement pessimistic locking instead - either at the database or application level. In other words, the process is:

  1. user wants to edit entity
  2. check if lock exists on entity
  3. YES - prohibit editing (allow read-only view?)
  4. NO - lock entity, allow editing
  5. commit (cancel) changes; release lock

Be sure to expire existing locks after a certain period of user inactivity if you go with this approach.


concurrently modifying1 is not really accurate in this case (that's what transactions are for); we're talking about preventing one thread from overwriting edits of another based on older version.

好菇凉咱不稀罕他 2024-08-11 21:15:47

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

Take a look at NHProf. It can help you with all kind of things related to Nhibernate profiling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文