捕获 ConstraintViolationException 并处理独特的约束

发布于 2024-10-20 08:06:18 字数 656 浏览 6 评论 0原文

我对 Hibernate 真的很不满!

我有一个数据库表(mysql),它保存父子关系,允许我构建类别树。我有多个线程可以尝试获取,如果没有,则大致在同一时间创建类别路径(隐含多个父子行)。

问题是我只使用 TRANSACTION_READ_COMMITTED,因此当线程可以为类别子路径创建父子路径时可能会发生竞争条件,因为它没有找到它,然后(瞧!)另一个线程在同一时间。为了尝试解决这个问题,我对父/子 ID 施加了唯一约束,并对完整类别路径施加了唯一约束。然后,我希望在我的会话中,我能够捕获 hibernate ConstraintViolationException,并且知道另一个线程为我写入了新关系,我查询另一个线程在 catch 子句中写入的行。并尝试继续在该线程中执行会话需要执行的所有操作。

这是我能想到的解决多个线程同时执行获取/创建相同长类别路径(具有多个子父子关系行)工作的问题的唯一方法,并确保唯一约束是坚持。

但是 hibernate 使 ConstraintViolationException 上的会话无效,并最终抛出断言异常(“com.stagirite.bean.Category 条目中的 null id(发生异常后不要刷新会话)”),因此我的解决方案不可行。

我如何在不使用悲观锁的情况下,在不创建重复行的“获取/创建”模型的整个应用程序中解决这个问题?

安迪

I'm really upset with Hibernate!

I have a database table (mysql) that holds parent-child relationships that allow me to build a tree of categories. I have multiple threads which can try to get and if not there create the category path (with several parent-child rows implied) at roughly the same time.

The problem is that I'm using TRANSACTION_READ_COMMITTED only, and so race conditions can occur where a thread can create a parent-child for a category subpath because it didn't find it, and then (lo!) another thread did this at the same time. To try to solve this problem, I put a unique constraint on the parent/child ids and a unique constraint on the full category path. Then, I hoped that in my session, I would catch the hibernate ConstraintViolationException, and knowing that another thread wrote the new relationship for me, I query for the row that the other thread wrote in the catch clause. And try to continue in that thread doing all the things it needs to do with the session.

This is the ONLY way I can think of to solve the problem of multiple threads doing the work of get/creating the same long category path (with several sub parent-child relationship rows) at the same time, and ensuring that the unique constraint is upheld.

But hibernate invalidates the session on ConstraintViolationException and ultimately throws an assertion exception ("null id in com.stagirite.bean.Category entry (don't flush the Session after an exception occurs)") so my solution is unviable.

How am I going to solve this throughout my application for "get/create" models that don't create duplicate rows, without using a pessimistic lock?

Andy

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

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

发布评论

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

评论(2

笨笨の傻瓜 2024-10-27 08:06:18

这个问题是很久以前的事了,但我最近遇到了这个问题。

至少我知道解决这个问题的两个选项:

A)在单独的新会话中创建新的父/子关系(新记录)并提交事务或捕获这些异常。
关闭新会话并重新读取上一个会话中的记录。

B) 在父记录上使用带有“选择更新”的专用锁。然后创建子记录。
这样,所有并发子创建者都会在父记录上同步。

The question is quite some time ago, but I faced this issue recently.

At least I know 2 options to solve this:

A) create the new parent/child relation (new record) in a separate new session and commit the transaction or catch those exceptions there.
Close the new session and re-read the record in the previous session.

B) use a dedicated lock with „select for update“ on parent record. Then create the child record.
This way all concurrent child creators are synchronized on the parent record.

白云不回头 2024-10-27 08:06:18

由于我不确定您如何建模数据(自引用表或物化路径)和相应的休眠映射,因此我将尝试回答两个线程试图更改同一事物的部分。您是否尝试过使用休眠版本控制功能。简而言之,如果一个线程已经更新了一个类别,则版本号会递增。可能已开始更新但未完成的另一个线程将看到版本更改和回滚。如果您可以发布您的数据模型,将会有所帮助。

希望有帮助。

Since I am not sure of how you have modelled your data (Self referential table or marterialized path) and the corresponding hibernate mapping, I am going to attempt answering the part where two threads are trying to change the same thing. Have you tried using the hibernate versioning feature. In short with versioning if one thread has already updated a category, the version number is incremented. The other thread which may have started the update but did not finish it will see the version change and rollback. It would help if you could post your data model.

Hope that helps.

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