首先让我们忘记hibernate。假设我有两个表A和B。两个事务正在更新这两个表中的相同记录,但是txn 1更新B然后A,而txn 2更新A然后B。这是一个典型的死锁示例。避免这种情况的最常见方法是预先定义获取资源的顺序。例如,我们应该先更新表A然后再更新表B。
回到hibernate状态。当我们在一个会话中更新大量实体时,一旦刷新会话,对不同实体的更改将为数据库生成相应的插入/更新/删除语句。Hibernate是否有某种算法来决定实体之间的更新顺序?如果不是,那么第1段所述的Hibernate用来防止死锁情况的方式是什么?
如果Hibernate正在维护订单,我如何知道或控制订单?我不希望在与Hibernate发生数据库冲突时进行显式更新,并导致死锁。
您描述的问题不是由数据库处理的,根据我的经验,Hibernate也不能完全解决该问题。
您必须采取明确的步骤来避免出现问题。
Hibernate为您完成了一些工作。按照前面的答案,Hibernate确保在单独的刷新中按一定的顺序对插入,删除和更新进行排序,以确保按可实现的顺序应用它们。请参见AbstractFlushingEventListener类中的performExecutions(EventSource会话):
以特殊顺序执行所有SQL(和二级缓存更新),以免违反外键约束: 按执行顺序插入 更新 删除收集元素 插入收集元素 按执行顺序删除
以特殊顺序执行所有SQL(和二级缓存更新),以免违反外键约束:
当具有唯一性约束时,了解此顺序非常重要,尤其是如果您要替换一对多子代(删除旧的/插入新的)时,新旧子代共享相同的唯一性约束(例如,相同的电子邮件地址) )。在这种情况下,您可以更新旧条目,而不是删除/插入,或者可以仅在删除后刷新,然后继续插入。有关更详细的示例,请查看本文。
请注意,它没有指定更新顺序。检查Hibernate代码使我认为更新顺序将取决于在实体被添加到持久化上下文中,为了在 不 他们更新的顺序。这在您的代码中可能是可以预见的,但是阅读Hibernate代码并没有让我觉得我会依赖该顺序。
我可以想到三种解决方案: