在JPA / Hibernate中正确使用flush()

时间:2010-11-25 08:43:33

标签: java hibernate jpa transactions persistence

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

现在我得到了以下两个实体AB的场景(以一对一的关系,但没有由JPA强制或建模)。 A有一个复合PK,它是手动设置的,还有一个自动生成的IDENTITY字段recordId。应将此recordId写入实体B作为A的外键。我在一次交易中保存AB。问题是自动生成的值A.recordId在交易中不可用,除非我在em.flush()上调用em.persist()后明确调用A。 (如果我有一个自动生成的IDENTITY PK,那么该值会在实体中直接更新,但这不是这里的情况。)

在交易中使用时会em.flush()造成任何伤害吗?

3 个答案:

答案 0 :(得分:131)

em.flush()的确切细节可能与实现有关。 总的来说,像Hibernate这样的JPA提供程序可以缓存它们应该发送到数据库的SQL指令,通常直到你实际提交事务为止。 例如,你调用em.persist(),Hibernate记得它必须创建一个数据库INSERT,但在提交事务之前实际上并不执行该指令。 Afaik,这主要是出于性能原因。

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

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

底线:没有造成任何伤害,只有你可以有一个(次要)性能命中,因为你重写JPA提供程序决定关于将SQL指令发送到数据库的最佳时机。

答案 1 :(得分:2)

实际上,em.flush()不仅仅发送缓存的SQL命令。它尝试将持久性上下文与基础数据库同步。如果缓存包含要同步的集合,则可能会导致流程耗费大量时间。

小心使用它。

答案 2 :(得分:1)

  

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

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

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

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