关于Java:在JPA / Hibernate中正确使用flush()

Correct use of flush() in JPA/Hibernate

我当时正在收集有关flush()方法的信息,但是我不清楚何时使用它以及如何正确使用它。从我的阅读中,我的理解是持久性上下文的内容将与数据库同步,即。 e。发布未完成的语句或刷新实体数据。

现在,我得到了具有两个实体AB的情况(一对一关系,但未由JPA强制执行或建模)。 A具有手动设置的复合PK,还具有自动生成的IDENTITY字段recordId。此recordId应该作为A的外键写入实体B。我要在单个事务中保存AB。问题是,除非在A上调用em.persist()后做出显式调用em.flush(),否则自动生成的值A.recordId在事务内不可用。 (如果我有一个自动生成的IDENTITY PK,那么该值将直接在实体中更新,但是这里不是这种情况。)

在事务中使用em.flush()会造成任何伤害吗?


em.flush()的确切细节可能取决于实现。
总之,无论如何,像Hibernate这样的JPA提供程序可以缓存应该发送给数据库的SQL指令,通常直到您真正提交事务为止。
例如,您调用em.persist(),Hibernate记住它必须使数据库INSERT,但实际上直到提交事务后才执行指令。 Afaik,这样做主要是出于性能方面的考虑。

在某些情况下,无论如何,您都希望立即执行SQL指令。通常,当您需要某些副作用(例如自动生成的密钥或数据库触发器)的结果时。

em.flush()的作用是清空内部SQL指令缓存,然后立即将其执行到数据库。

底线:不会造成任何伤害,因为您将优先考虑将JPA提供程序发送到数据库的最佳时间,因为您要覆盖JPA提供程序的决定,因此对性能的影响不大。


实际上,em.flush()的作用不只是发送缓存的SQL命令。它尝试将持久性上下文同步到基础数据库。如果您的缓存包含要同步的集合,则可能会在您的进程上浪费大量时间。

小心使用。


Can em.flush() cause any harm when using it within a transaction?

是的,它在数据库中的锁定时间可能比必要的时间长。

通常,使用JPA时,您将事务管理委托给容器(也称为CMT-在业务方法上使用@Transactional批注),这意味着在输入方法时自动启动事务,并在最后提交/回滚。如果让EntityManager处理数据库同步,则将仅在提交之前触发sql语句执行,从而导致数据库中的锁短暂存在。否则,您的手动刷新的写操作可能会在手动刷新和自动提交之间保留锁,根据其他方法的执行时间,锁可能会很长。

请注意,某些操作会自动触发刷新:针对同一会话执行本地查询(EM状态必须刷新才能通过SQL查询访问),使用本地生成的ID(由数据库生成)插入实体,因此insert语句必须为触发,因此EM能够检索生成的ID并正确管理关系)