【问题标题】:What is exact purpose of flush in JPAJPA中flush的确切目的是什么
【发布时间】:2015-11-13 12:28:32
【问题描述】:

一些令人困惑的解释: 冲洗();刷新是将底层持久存储与内存中保存的持久状态同步的过程。它会在正在运行的事务中更新或插入表中,但它可能不会提交这些更改。

如果无论如何更改都只会在提交后保留在数据库中,那么为什么要在代码中间刷新。

并且在运行刷新之后,如果对托管对象进行了任何更改,那么这将引发异常,或者那些会被同步,然后将被持久化。如果它们再次同步,那么为什么要首先刷新。

【问题讨论】:

标签: java jpa entitymanager


【解决方案1】:

理论上,您(作为 JPA 的用户)永远不应该(或在极少数情况下)拨打flush()

刷新是同步底层持久化的过程 存储在内存中的持久状态

换句话说,在flush() 上,数据库上实际调用了所有插入、更新、删除或任何语句,在flush() 之前,您的数据库上什么也没有发生。刷新是由事务的提交或某些类型的数据库读取引起的。例如,如果您执行 JPQL 查询,则必须执行 flush() 才能从数据库中获取正确的结果。但这很高兴知道并完全由您的 JPA 实现处理。

在某些情况下,您可能希望自己控制此刷新,然后您可以使用flush() 调用它。

编辑回答评论中的问题:

并非每次读取都需要刷新,请考虑这种情况(一个事务):

  1. 读一个人Person p = em.find(Person.class, 234)
  2. 更新人p.setAge(31)
  3. 读取建筑物Building b = em.find(Building.class, 123
  4. 使用 JPQL 查询读取建筑物 select b from Building b where b.id = 123

自动flush只发生在 4. 之前,因为 Eclipselink 不能确定你要读什么,所以这个人的年龄必须在数据库上是最新的,才能进行这个读操作。 3. 之前不需要刷新,因为 Eclipselink 知道对人的更新不会影响建筑物。

要使用乐观锁定,您必须实现它。在此处阅读@Version 注释:https://blogs.oracle.com/carolmcdonald/entry/jpa_2_0_concurrency_and。否则,您的实体将不会使用乐观锁定并且“最后更新获胜”。

【讨论】:

  • 那么如果我对数据库进行读取,是否会在自动读取之前调用刷新?
  • 还有一个小问题,如果一个线程刷新实体上的一些数据,而另一个线程对其进行一些更改并在自己的事务中进行刷新,它是否会抛出一个乐观锁,我我只是想知道,因为就像您说的那样,刷新的数据仅与欠款交易隔离,对其他人不可见。那么其他线程会不会导致乐观锁呢?
  • 我在上面的回答中回答了你的问题,但是提出一个关于 SO 的新的具体问题而不是“扩展”这个问题,这可能对其他人没有帮助。
【解决方案2】:

当事务提交时,实体管理器会为您进行刷新。在某些情况下,例如在容器管理的事务中处理乐观锁定,您可能需要手动调用 flush 方法来捕获和处理特定的锁定异常。

【讨论】:

  • 但是当我刷新时,我没有看到数据库中的数据已更新。 SO上的一些教程和一些问题提到刷新只会将数据移动到二级缓存。我不知道这意味着什么,但由于数据不在数据库中,我不知道它是否有用
  • 我记得,这也是实体管理器使用的相同刷新方法。如果更新未反映在数据库中,则必须在提交过程中引发异常。在一系列事务事件之后,它可能是一些不同步的持久性上下文。
  • @NickDiv 一个简单的例子:persist -> memory / flush -> database (isolated, not visible to others) / commit -> 数据库(对其他人可见)。了解数据库事务。
  • 如果您怀疑这是缓存问题,您可以尝试通过 persistence.xml 配置文件禁用缓存。将shared-cache-mode 设置为NONE
  • @OwenBringino 非常感谢您的回答。缓存似乎不是问题。也没有异常被抛出。我不知道为什么我看不到数据库中的数据。刷新的数据是否可以回滚?
猜你喜欢
  • 2011-01-21
  • 1970-01-01
  • 2015-06-02
  • 2016-11-24
  • 2011-05-15
  • 2013-08-13
  • 2015-10-04
  • 1970-01-01
相关资源
最近更新 更多