Hibernate如何决定更新/插入/删除的顺序

Adr*_*hum 32 deadlock hibernate database-deadlocks

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

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

如果Hibernate维护订单,我怎么知道或控制订单?我不希望我的数据库中的显式更新与Hibernate冲突,并导致死锁.

Dav*_*rds 40

您描述的问题不是由数据库处理的,根据我的经验,Hibernate也没有完全处理.

你必须采取明确的步骤来避免它成为一个问题.

Hibernate为您完成了一些工作.根据之前的回答,Hibernate确保在隔离的刷新内对插入,删除和更新进行排序,以确保它们以可实现的顺序应用.请参阅AbstractFlushingEventListener类中的performExecutions(EventSource会话):

以特殊顺序执行所有SQL(和二级缓存更新),以便不会违反外键约束:

  1. 按插入顺序执行插入
  2. 更新
  3. 删除集合元素
  4. 插入集合元素
  5. 按照执行顺序删除

当具有唯一约束时,了解此顺序非常重要,特别是如果要替换一对多子(删除旧/插入新),但旧子和新子共享相同的唯一约束(例如,相同的电子邮件地址) ).在这种情况下,您可以更新旧条目,而不是删除/插入,或者您可以在删除后刷新,然后继续插入.有关更详细的示例,您可以查看本文.

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

我能想到三种解决方案:

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

  • 请接受我的道歉,因为未知的原因,我之前错过了这个答案:)我相信到目前为止,您在Hibernate代码中的检查结果实际上给出了最可信赖的答案。好的建议,尤其是针对第1点和第2点 (2认同)