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-flushingflush()
很有用,因为绝对不能保证 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
和 HibernateSession
暴露了一组方法,通过这些方法 应用程序开发人员可以更改实体的持久状态。持久性上下文充当事务性后写缓存, 排队任何实体状态更改。像任何后写缓存一样,更改 首先在内存中应用并在期间与数据库同步 冲洗时间。刷新操作需要每个实体状态更改和 将其转换为
INSERT
、UPDATE
或DELETE
语句。刷新策略由当前的flushMode给出 运行休眠会话。虽然 JPA 只定义了两次刷新 策略(
AUTO
和COMMIT
),Hibernate 有很多 更广泛的冲洗类型:ALWAYS
:在每次查询之前刷新 Session;AUTO
:这是默认模式,仅在必要时刷新会话;COMMIT
: Session 尝试延迟刷新,直到当前事务被提交,尽管它也可能过早刷新;MANUAL
:会话刷新被委托给应用程序,它必须显式调用Session.flush()
才能应用 持久性上下文更改。默认情况下,Hibernate 使用
在提交交易之前; 在执行与排队实体操作重叠的 JPQL/HQL 查询之前; 在执行任何未注册同步的本机 SQL 查询之前。AUTO
刷新模式,该模式会触发 在以下情况下刷新:
【讨论】:
【参考方案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() 有啥用的主要内容,如果未能解决你的问题,请参考以下文章
Session.flush() 导致 org.hibernate.StaleStateException:批量更新从更新返回了意外的行数:1 实际行数:0 预期:1