在 JPA/休眠中正确使用 flush()

2022-08-31 08:35:34

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

现在,我遵循了两个实体和(在一对一关系中,但不是由JPA强制执行或建模)的场景。 具有手动设置的复合PK,并且还具有 自动生成的IDENTITY字段 。这应该作为 外键写入实体。我正在储蓄并在一笔交易中。问题在于,自动生成的值在事务中不可用,除非我在调用 .(如果我有一个自动生成的IDENTITY PK,那么该值将直接在实体中更新,但这里的情况并非如此。ABArecordIdrecordIdBAABA.recordIdem.flush()em.persist()A

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


答案 1

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

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

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

底线:没有造成任何伤害,只有您可能会受到(轻微的)性能影响,因为您正在覆盖JPA提供程序关于向数据库发送SQL指令的最佳时机的决定。


答案 2

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

是的,它可能会在数据库中保留锁的时间超过必要的时间。

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

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


推荐