Hibernate 中 session.flush() 有啥用

Posted

技术标签:

【中文标题】Hibernate 中 session.flush() 有啥用【英文标题】:What's the use of session.flush() in HibernateHibernate 中 session.flush() 有什么用 【发布时间】:2011-03-14 07:35:21 【问题描述】:

当我们更新记录时,我们可以在 Hibernate 中使用session.flush()flush()需要什么?

【问题讨论】:

【参考方案1】:

刷新会话会强制 Hibernate 将 Session 的内存状态与数据库同步(即将更改写入数据库)。默认情况下,Hibernate 会自动为您刷新更改:

在一些查询执行之前 提交事务时

允许显式刷新Session 可以提供在某些情况下可能需要的更好控制(获取分配的 ID、控制 Session 的大小......)。

【讨论】:

请注意,此答案描述了默认休眠行为:可以通过刷新模式设置更改刷新行为。详细信息在docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/…(3.5 版)中。 我找到了document,它的内容与您所说的完全一致,但我有疑问,假设优先级是什么 1) 我有使用代码 id = session.save(obj); 保存对象的类和事务在下一行提交,但 obj 没有保存到 DB,为什么? 2) 我使用session.save(obj); 保存了 obj 并在返回时使用了return obj.getprimaryID(); 在这种情况下,obj 被保存到 DB。那么为什么会发生这种行为呢?【参考方案2】:

正如上面答案中所说的那样,通过调用flush(),我们强制休眠在数据库上执行 SQL 命令。但请理解更改尚未“承诺”。 因此,在刷新之后和提交之前,如果您直接访问数据库(例如从 SQL 提示符)并检查修改的行,您将看不到更改。

这与打开 2 个 SQL 命令会话相同。并且在 1 个会话中完成的更改在提交之前对其他人不可见。

【讨论】:

嗯 - 更改可能会稍微可见。例如,未提交的行可以在已插入但未提交的行上创建锁,并延迟同一行被另一个会话插入,直到事务被提交或回滚。所以它不是完全不可见的。 我浏览了整个网络,这就是最终让我明白的答案。谢谢。 将 .flush() 放在 for 循环中然后如果 commit() 在最后执行刷新有什么用? @Kaushik Lele 如果刷新后数据不可见,那么刷新()的意义何在?您能否详细说明一些可以派上用场的更精细的用例?【参考方案3】:

我只知道当我们调用session.flush() 时,我们的语句在数据库中执行但没有提交。

假设我们不在会话对象上调用flush() 方法,如果我们调用commit 方法,它将在内部完成在数据库上执行语句然后提交的工作。

commit=flush+commit(在功能的情况下)

因此,我得出结论,当我们在 Session 对象上调用方法 flush() 时,它不会得到提交,而是命中数据库并执行查询并得到回滚。

为了提交,我们在 Transaction 对象上使用 commit()。

【讨论】:

你能详细说明一下flush需要什么吗?【参考方案4】:

刷新 Session 获取当前在会话中的数据与数据库中的数据同步。

Hibernate 网站上的更多信息:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-flushing

flush() 很有用,因为绝对不能保证 Session 何时执行 JDBC 调用,只能保证它们的执行顺序 - 除非您使用 flush()

【讨论】:

你能提供一个用户应该担心序列的场景吗?使用休眠是为了让数据库相关的东西对用户透明。当我们“提交”时,刷新会自动发生。什么情况下会刷新但不提交? @KaushikLele 你可以参考这个问题***.com/questions/37382872/…【参考方案5】:

您可以使用flush 来强制在已知位置而不是在提交事务时实现和检测验证约束。 commit 可能被某些框架逻辑、通过声明性逻辑、容器或模板隐式调用。在这种情况下,任何抛出的异常都可能难以捕获和处理(它可能在代码中太高了)。

例如,如果您save() 一个新的 EmailAddress 对象,该对象对地址具有唯一约束,则在您提交之前不会收到错误。

调用flush() 强制插入行,如果有重复则抛出异常。

但是,您必须在异常发生后回滚会话。

【讨论】:

【参考方案6】:

flush() 方法导致 Hibernate 刷新会话。您可以使用 setFlushMode() 方法将 Hibernate 配置为对会话使用刷新模式。要获取当前会话的刷新模式,可以使用getFlushMode() 方法。要检查会话是否脏,可以使用isDirty() 方法。默认情况下,Hibernate 管理会话的刷新。

如文档中所述:

https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/flushing/Flushing.html

冲洗

flushing是同步持久化状态的过程 与底层数据库的上下文。 EntityManager 和 Hibernate Session 暴露了一组方法,通过这些方法 应用程序开发人员可以更改实体的持久状态。

持久性上下文充当事务性后写缓存, 排队任何实体状态更改。像任何后写缓存一样,更改 首先在内存中应用并在期间与数据库同步 冲洗时间。刷新操作需要每个实体状态更改和 将其转换为 INSERTUPDATEDELETE 语句。

刷新策略由当前的flushMode给出 运行休眠会话。虽然 JPA 只定义了两次刷新 策略(AUTOCOMMIT),Hibernate 有很多 更广泛的冲洗类型:

ALWAYS:在每次查询之前刷新 Session; AUTO:这是默认模式,仅在必要时刷新会话; COMMIT: Session 尝试延迟刷新,直到当前事务被提交,尽管它也可能过早刷新; MANUAL:会话刷新被委托给应用程序,它必须显式调用 Session.flush() 才能应用 持久性上下文更改。

默认情况下,Hibernate 使用AUTO 刷新模式,该模式会触发 在以下情况下刷新:

在提交交易之前; 在执行与排队实体操作重叠的 JPQL/HQL 查询之前; 在执行任何未注册同步的本机 SQL 查询之前。

【讨论】:

【参考方案7】:

我只想将上面给出的所有答案都包含在内,并将 Flush() 方法与 Session.save() 联系起来,以便更加重视

Hibernate save() 可用于将实体保存到数据库。我们可以在事务之外调用这个方法,所以我不喜欢用这个方法来保存数据。如果我们在没有事务的情况下使用它并且我们在实体之间有级联,那么除非我们刷新会话,否则只有主实体会被保存。

flush():强制会话刷新。用于将会话数据与数据库同步。

当您调用 session.flush() 时,语句在数据库中执行但不会提交。 如果您不调用 session.flush() 并且如果您调用 session.commit() ,则内部 commit() 方法会执行该语句并提交。

所以提交()=刷新+提交。 所以 session.flush() 只是执行数据库中的语句(而不是提交)并且语句不再在内存中。它只是强制会话刷新。

几个重点:

我们应该避免在事务边界之外保存,否则映射的实体将不会被保存导致数据不一致。忘记刷新会话是很正常的,因为它不会引发任何异常或警告。 默认情况下,Hibernate 会自动为您刷新更改: 在一些查询执行之前 提交事务时 允许显式刷新 Session 提供了在某些情况下可能需要的更好的控制(获取分配的 ID,控制 Session 的大小)

【讨论】:

【参考方案8】:

调用EntityManager#flush 确实有副作用。它方便地用于具有生成 ID 值(序列值)的实体类型:这样的 ID 仅在与底层持久层同步时可用。如果在当前事务结束之前需要此 ID(例如用于记录目的),则需要刷新会话。

【讨论】:

【参考方案9】:

使用此方法可以调用刷新过程。这个过程同步 通过检测状态变化并执行相应的 SQL 语句,将数据库的状态与会话的状态结合起来。

【讨论】:

以上是关于Hibernate 中 session.flush() 有啥用的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate session flush

Session.flush() 导致 org.hibernate.StaleStateException:批量更新从更新返回了意外的行数:1 实际行数:0 预期:1

hibernate学习(六) flush()和clean()区别和使用

休眠:flush()和commit()

hibernate 批量插入

Hibernate