Hibernate中session.flush()有什么用


110

更新记录时,可以session.flush()与Hibernate一起使用。有什么需要flush()

Answers:


138

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

  • 在执行某些查询之前
  • 进行交易时

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


8
请注意,此答案描述了默认的休眠行为:可以通过“刷新模式”设置更改刷新行为。详细信息在docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/…(3.5版)中。
2012年

1
我在文档中找到了与您说的完全相同的文档,但是我有一个问题,那就是优先级是什么?假设1)我有一个类,其中我使用代码保存对象,id = session.save(obj);并且在下一行提交了事务,但是没有保存obj到数据库,为什么?2)我使用session.save(obj);commit 保存了obj ,并在返回时使用了return obj.getprimaryID();obj,在这种情况下,obj保存到了DB。那么为什么会发生这种现象呢?
Amogh

74

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

这与打开2个SQL命令会话相同。在一次会话中完成的更改只有在提交后才对其他人可见。


12
好吧-这些更改可能会稍微可见。例如,未提交的行可以在插入但未提交的行上创建锁,并延迟同一行被另一个会话插入,直到事务被提交或回滚为止。因此它不是完全看不见的。
rghome 2015年

2
我已经在网上冲浪了,这就是最终使我明白的答案。谢谢。
悉达多

将.flush()放入for循环有什么用,然后如果commit()最后进行刷新,有什么用?
Eildosa

@Kaushik Lele如果刷新后看不到数据,flush()的意义是什么?您能否详细说明一些较方便的用例?
java_geek

28

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

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

commit=flush+commit (如果有功能)

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

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


您能提供一些有关需要冲洗的细节吗?
java_geek

14

刷新会话将使会话中当前的数据与数据库中的数据同步。

Hibernate网站上的更多信息:

flush()之所以有用,是因为绝对不保证会话何时执行JDBC调用,仅保证它们执行的顺序(除非您使用)flush()


您可以提供一种让用户担心顺序的方案吗?休眠的用途是使数据库相关的内容对用户透明。当我们进行“提交”时,将自动进行冲洗。在什么情况下您将执行刷新但不提交?
Kaushik Lele 2015年

1
@KaushikLele你可以参考这个问题stackoverflow.com/questions/37382872/...
GMsoF

10

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

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

调用将flush()强制插入行,如果重复则抛出Exception。

但是,在异常之后,您将必须回滚会话。


4

我只想总结以上给出的所有答案,并将Flush()方法与Session.save()关联起来,以便更加重视

Hibernate save()可用于将实体保存到数据库。我们可以在事务外部调用此方法,这就是为什么我不喜欢此方法保存数据的原因。如果我们在不使用事务的情况下使用它,并且在实体之间进行级联,那么只有主实体会被保存,除非刷新会话。

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

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

所以commit()= flush + commit。因此,session.flush()仅执行数据库中的语句(但不执行提交),并且语句不再处于内存中。它只是强制会话刷新。

几个要点:

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


3

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

如文档中所述:

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

冲洗

刷新是将持久性上下文的状态与基础数据库同步的过程。的EntityManager和休眠Session暴露了一组方法,通过该应用程序开发者可改变的实体的持久状态。

持久性上下文充当事务后写式高速缓存,对任何实体状态更改进行排队。像任何后写式缓存一样,更改首先会在内存中应用,并在刷新期间与数据库同步。冲洗操作需要每一个实体的状态变化,并将其转换到INSERTUPDATEDELETE声明。

刷新策略由当前运行的Hibernate会话的flushMode给出。尽管JPA仅定义了两种刷新策略(AUTOCOMMIT),但是Hibernate具有更广泛的刷新类型范围:

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

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

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

1

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


0

使用此方法,您可以触发刷新过程。该过程通过检测状态更改并执行相应的SQL语句,将数据库状态与会话状态同步。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.