Hibernate如何决定更新/插入/删除的顺序 [英] How is Hibernate deciding order of update/insert/delete

查看:162
本文介绍了Hibernate如何决定更新/插入/删除的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

先让我们忘掉Hibernate。假设我有两张表,A& B.两个事务正在更新这两个表中的相同记录,但txn 1更新B然后A,而txn 2更新A然后B.这是一个典型的死锁示例。避免这种情况的最常见方法是预先定义获取资源的顺序。例如,我们应该更新表A然后B。



回到Hibernate。当我们在一个会话中更新大量实体时,一旦我正在刷新会话,不同实体的更改将为DB生成相应的插入/更新/删除语句。 Hibernate是否有一些算法来决定实体之间的更新顺序?如果没有,Hibernate用来防止第一段中描述的死锁情况的方式是什么?



如果Hibernate维护顺序,我怎么知道或控制顺序?我不希望自己的显式更新与Hibernate的数据库冲突,并导致死锁。

我的经验并不完全由Hibernate来处理。



您必须采取明确步骤避免它成为问题。



Hibernate为你做了一些工作。根据之前的答案,Hibernate确保在隔离的flush中插入,删除和更新的顺序可以确保它们以可实现的顺序应用。请参阅
$ b


执行所有SQL(和second-它们是按照特殊顺序进行的,以便不会违反外键约束:


  1. 插入按照它们执行的顺序 li>
  2. 更新

  3. 删除集合元素

  4. 插入集合元素 >按执行的顺序删除


当有独特的约束时,知道这一点非常重要顺序,特别是如果你想要替换一对多的孩子(删除旧的/插入新的),但旧的和新的孩子共享相同的唯一约束(例如相同的emai l地址)。在这种情况下,您可以更新旧条目,而不是删除/插入,也可以在删除后进行刷新,然后继续插入。有关更详细的示例,您可以查看这篇文章



请注意,它没有指定更新的顺序。检查Hibernate代码让我认为更新顺序将取决于实体添加到持久化上下文的顺序, NOT 它们更新的顺序。这可能在你的代码中是可以预测的,但是阅读Hibernate代码并没有让我觉得我会依赖这个顺序。



我能想到的有三种解决方案: / p>


  1. 尝试设置 hibernate.order_updates true 。这应该有助于避免在同一个表中的多行被更新时发生死锁,但是不会有助于跨多个表的死锁。
  2. 使您的事务处理为 PESSIMISTIC_WRITE 在进行任何更新之前锁定其中一个实体。您使用哪个实体将取决于您的具体情况,但只要您确保在存在死锁风险的情况下一致地选择实体,就会阻止事务的其余部分,直至获得锁定。
  3. b $ b
  4. 编写代码,以便在出现死锁时以合理的方式重试。管理死锁重试的组件必须位于当前事务边界之外。这是因为失败的会话必须关闭并且关联的事务回滚。在这篇文章中,您可以找到自动重试AOP方面的示例。


Let's first forget about Hibernate. Assume that I have two tables, A & B. Two transactions are updating same records in these two tables, but txn 1 update B and then A, while txn 2 update A then B. This is a typical deadlock example. The most common way to avoid this is by pre-defining the order of acquiring resources. For example, we should update table A then B.

Go back to Hibernate. When we are updating lots of entities in one session, once I am flushing the session, changes of different entities is going to generate corresponding insert/update/delete statements to DB. Does Hibernate have some algorithm to decide the order of update among entities? If not, what is the way Hibernate used to prevent deadlock situation described in 1st paragraph?

If Hibernate is maintaining the order, how can I know or control the order? I don't want my explicit update in DB conflicts with Hibernate, and cause deadlock.

解决方案

The problem you describe is not handled by the database, and from my experience is not entirely handled by Hibernate either.

You have to take explicit steps to avoid it being a problem.

Hibernate does some of the work for you. As per the previous answer, Hibernate ensures that within an isolated flush the inserts, deletes and updates are ordered in a way that ensures that they will be applied in an achievable order. See performExecutions(EventSource session) in the AbstractFlushingEventListener class:

Execute all SQL (and second-level cache updates) in a special order so that foreign-key constraints cannot be violated:

  1. Inserts, in the order they were performed
  2. Updates
  3. Deletion of collection elements
  4. Insertion of collection elements
  5. Deletes, in the order they were performed

When having unique constraints it's very important to know this order, especially if you want to replace a one-to-many child (delete old/insert new) but both the old and the new child share the same unique constraints (e.g. same email address). In this case you could update the old entry, instead of deleting/inserting, or you could flush after delete only to then continue inserting. For a more detailed example you can check this article.

Note that it does not specify the order of updates. Examining the Hibernate code leads me to think the update order will depend on the order in which the entities were added to the persistence context, NOT the order they were updated. That might be predictable in your code, but reading the Hibernate code did not leave me feeling I would rely on that ordering.

There are three solutions I can think of:

  1. Try setting hibernate.order_updates to be true. This should help avoid deadlocks when multiple rows in the same table are being updated, but won't help with deadlocks across multiple tables.
  2. Make your transactions take a PESSIMISTIC_WRITE lock on one of the entities before doing any updates. Which entity you use will depend on your specific situation, but so long as you ensure an entity is chosen consistently if there is a risk of deadlock, this will block the rest of the transaction until the lock can be obtained.
  3. Write your code to catch deadlocks when they occur and retry in a sensible fashion. The component managing the dead-lock retry must be located outside of the current transaction boundary. This is because the failing session must be closed and the associated transaction roll-backed. In this article you can find an example of an automatic retrying AOP Aspect.

这篇关于Hibernate如何决定更新/插入/删除的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆