当前位置: 首页 > 知识库问答 >
问题:

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

冯澄邈
2023-03-14

让我们先忘记Hibernate。假设我有两张表,一张

回去冬眠吧。当我们在一个会话中更新大量实体时,一旦我刷新会话,不同实体的更改将会向数据库生成相应的插入/更新/删除语句。Hibernate有什么算法来决定实体之间的更新顺序吗?如果不是,Hibernate用来防止第一段描述的死锁情况的方法是什么?

如果Hibernate正在维持订单,我如何知道或控制订单?我不希望我在数据库中的显式更新与Hibernate冲突,从而导致死锁。

共有2个答案

窦成荫
2023-03-14

关于第一个例子——这种东西是由数据库处理的(阅读有关数据库的事务隔离级别和锁定策略的更多信息)。有许多不同的方法可以处理这一点。

至于Hibernate,javadoc to org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(EventSource)说:

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

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

我假设这是Hibernate执行的SQL查询的唯一优化。其余问题由数据库处理。

何甫
2023-03-14

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

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

HiberNate为您做了一些工作。根据前面的答案,HiberNate确保在隔离刷新中对插入、删除和更新进行排序,以确保它们将以可实现的顺序应用。请参阅AbstractFlashingEventListener类中的performExections(EventSource会话):

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

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

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

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

我能想到三种解决方案:

  1. 尝试设置Hibernate。order_updates设置为true。当更新同一表中的多行时,这将有助于避免死锁,但对跨多个表的死锁没有帮助
  2. 在进行任何更新之前,使您的事务在其中一个实体上获得PESIMISTIC_WRITE锁。您使用的实体将取决于您的具体情况,但只要您确保在存在死锁风险的情况下一致选择实体,这将阻止事务的其余部分,直到可以获得锁
  3. 编写代码以在死锁发生时捕获死锁,并以合理的方式重试。管理死锁重试的组件必须位于当前事务边界之外。这是因为必须关闭失败的会话并回滚关联的事务。在本文中,您可以找到一个自动重试AOP方面的示例
 类似资料:
  • 问题内容: 首先让我们忘记hibernate。假设我有两个表A和B。两个事务正在更新这两个表中的相同记录,但是txn 1更新B然后A,而txn 2更新A然后B。这是一个典型的死锁示例。避免这种情况的最常见方法是预先定义获取资源的顺序。例如,我们应该先更新表A然后再更新表B。 回到hibernate状态。当我们在一个会话中更新大量实体时,一旦刷新会话,对不同实体的更改将为数据库生成相应的插入/更新/

  • 插入、更新和删除语句基于以开头的层次结构生成 UpdateBase . 这个 Insert 和 Update 构建基于中介的 ValuesBase . DML基础构造函数 顶级的“插入”、“更新”、“删除”构造函数。 Object Name Description delete(table[, whereclause, bind, returning, ...], **dialect_kw) 构建

  • 问题内容: 我只是对某事感到好奇。让我说我有一个表,我将更新该值,然后将其删除,然后插入新的1。如果我以这种方式编写代码,这将非常容易: 但是,如果使用“ update”语句,它将更加容易。但我的问题是,有可能同时完成这3个步骤吗? 问题答案: 引用Oracle事务处理语句文档: 事务是一个逻辑的 原子工作单元 ,包含一个或多个SQL语句。事务对SQL语句进行分组,以使它们要么全部提交(这意味着它

  • 我有一个由Access DB使用ResultSet&填充的JTable。我有一个方法可以正确地从数据库中删除记录,但在刷新表模型的当前视图时遇到了困难。我看过类似的帖子,并尝试使用和,但没有成功。我还注意到其他帖子提到了的使用,因为它有add/remove行方法,但我使用的代码来自我去年使用的Java教科书(教授从未达到这一点,所以我试图自己学习)... 以下是定制JFrame的类: 下面是Abs

  • 问题内容: 我实际上从未完全了解hibernate状态下的这种行为。我在名为“ Parent”的实体中使用@OneToMany关系,其注释如下: 现在,我想在一个事务中执行以下操作: 获取父实体 遍历孩子们的名单 删除其中一个孩子 插入一个新孩子 因此,基本上我只是完全替换其中一个孩子。 据我了解的这个问题,我应该能够做这样的事情:(请注意,这只是一些Java伪代码来说明问题) 但是,如果新的Ch

  • 现在我想在一个事务内执行以下操作: 获取父实体 遍历子级列表 删除其中一个子项 插入新子级 所以,基本上我只是完全替换了其中一个孩子。 由于我不想让hibernate混淆了发送到DB的语句的顺序,所以我对hibernate肯定有其他的假设,但情况并非如此。你知道为什么后一个例子有效,而第一个却不行吗? Hibernate版本为3.5。是Mysql InnoDB