JPA中flush的确切作用是什么?

26

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

如果更改无论如何都将在提交后才被持久化到数据库中,那么为什么要在代码中间刷新呢?

如果在运行刷新后对托管对象进行任何更改,那么是否会引发异常,还是这些更改将被同步并且然后得到持久化。如果它们被同步了,那么为什么要首先刷新呢?


看看这个,可能会有答案:https://dev59.com/E14c5IYBdhLWcg3wCGf2 - Brad Peabody
@bgp 一些答案说“flush仅在事务内使用?它刷新(但不提交),而commit提交数据(显然)”,这就是我的问题,所有这些中flush的目的是什么。 - Nick Div
3个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
20
理论上,你(作为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`,因为Eclipselink无法确定您要读取什么,因此必须在此读取发生之前将人的年龄更新到数据库。在第三个操作之前不需要刷新,因为Eclipselink知道对人的更新不会影响建筑物。

要使用乐观锁,您需要实现它。在此处阅读有关 @Version 注释的信息: https://blogs.oracle.com/carolmcdonald/entry/jpa_2_0_concurrency_and。如果没有实现它,您的实体将不使用乐观锁定并且“最后一次更新”会胜出。


如果我在数据库上执行读取操作,那么刷新操作会自动在读取之前调用吗? - Nick Div
1
还有一个小问题,如果一个线程在实体上刷新了一些数据,而另一个线程对其进行了更改并在自己的事务中进行了刷新,那么它会抛出乐观锁吗?我只是想知道,因为就像你所说的,刷新的数据仅隔离到拥有事务,不可见于其他人。那么其他线程会导致乐观锁吗? - Nick Div
我在上面的回答中解答了你的问题,但是建议你在Stack Overflow上提出一个新的具体问题,而不是“延伸”这个问题,这样可能对其他人更有帮助。 - Mathias Begert

3

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


2
但是当我执行flush操作时,我没有看到数据库中的数据更新。一些教程和一些SO上的问题提到flush只会将数据移动到第二级缓存中。虽然我不知道这意味着什么,但由于数据不在数据库中,我不知道它是否有用。 - Nick Div
据我记得,实体管理器也使用了相同的刷新方法。如果更新没有反映在数据库中,那么在提交过程中一定会抛出异常。这可能是一系列事务事件后未同步的持久化上下文出现的问题。 - owenrb
4
一个简单的例子:persist -> 内存 / flush -> 数据库(隔离,对其他人不可见)/ commit -> 数据库(对其他人可见)。请阅读有关数据库事务的内容。 - Mathias Begert
1
如果您怀疑这是缓存问题,可以尝试通过修改persistence.xml配置文件来禁用缓存。将shared-cache-mode设置为NONE - owenrb
@OwenBringino 非常感谢你的回答。缓存似乎不是问题所在。而且也没有抛出任何异常。我不知道为什么在数据库中看不到数据。有可能刷新的数据可以被回滚吗? - Nick Div
显示剩余2条评论

0
如果您手动持久化两个实体,您将需要生成的ID。
entityManagerInstance.persist(entity1);
entityManagerInstance.flush();
entity2.setForeignKeyToEntity1(entity1.getId());
entity2.create();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,