Entitymanager.flush() VS EntityManager.getTransaction().commit - 我应该更喜欢啥?

Posted

技术标签:

【中文标题】Entitymanager.flush() VS EntityManager.getTransaction().commit - 我应该更喜欢啥?【英文标题】:Entitymanager.flush() VS EntityManager.getTransaction().commit - What should I prefer?Entitymanager.flush() VS EntityManager.getTransaction().commit - 我应该更喜欢什么? 【发布时间】:2012-06-18 09:01:51 【问题描述】:

更新数据库时我应该更喜欢什么?这两种方法的优缺点是什么?我什么时候应该使用其中一种?

public void disemployEmployee(Integer employeeId, Date endDate) 
    Employee employee = (Employee)em.find("Employee", employeeId);
    employee.getPeriod().setEndDate(endDate);
    em.flush();


public void disemployEmployee(Integer employeeId, Date endDate) 
    Employee employee = (Employee)em.find("Employee", employeeId);
    em.getTransaction().begin();
    employee.getPeriod().setEndDate(endDate);
    em.getTransaction().commit();

【问题讨论】:

【参考方案1】:

在您的第一个示例中,数据的更改在遇到刷新后反映在数据库中,但它仍在事务中。

但在第二个示例中,您正在立即提交事务。因此,对数据库进行了更改,事务也到此结束。

有时,刷新可能有助于在正在进行的事务之间保留数据,然后最终提交更改。因此,如果之后出现问题,您也可以回滚之前的更改,例如批量插入/更新。

【讨论】:

第一个例子中没有事务,所以在flush()时抛出了异常。 @DataNucleus 我认为在 CMT 中,我们不必手动启动/结束事务。 确定,但他在 CMT 吗?在他的另一个例子中,他启动了 txn,所以这是我能做出的唯一假设 @NayanWadekar 我认为数据不会发送到数据库。它只在缓存中。您需要“提交”才能发送数据。 @TheProgrammer 不,更改会在刷新时立即反映出来,请参阅文档 - docs.oracle.com/javaee/6/api/javax/persistence/… & 这里有一些解释 - ***.com/a/17703822【参考方案2】:

您确实阅读了有关刷新和提交的 javadoc,并且知道刷新仅用于事务中?它刷新(但不提交),而提交提交数据(显然)。它们是不同的;没有“偏好”。第一个例子是错误的,应该会导致调用flush(TransactionRequiredException)的异常

【讨论】:

如果不使用flush(),我可以用flush()做什么? Flush 将数据放入数据存储中,没有它,数据就不存在,因此查询可以返回过时的数据。也许阅读有关flush()的JPA规范 好吧,API 所说的有关 flush() 的所有内容都是“将持久性上下文同步到底层数据库”,我以前从未使用过它,但我的事务在调用 EntityManager.getTransaction.commit() 时仍将数据放入数据库.而且我还没有调用EntityManager.flush()!所以我无法理解flush()的使用,即使没有它你也可以做它所做的一切。 是的,确实 commit 提交了数据(如前所述),为此,如果尚未将其刷新到数据存储区,则它会进行刷新。 flush() 只是让您可以选择更早地把它放在那里。 flush() 的一个用例是强制生成可以在同一事务中使用的 ID。例如,当您想要创建日志(在数据库内)或历史条目(基本上是副本)时。不使用这些条目与实际实体之间的关系的原因是,在这种情况下您不必担心 ID,因为您无法删除实体而不会由于外键而丢失日志/历史条目。跨度> 【参考方案3】:

您的两个代码示例都不会持久化或合并要写入数据库的实体状态。

我认为比较 EntityManager.flush()EnityManager.EntityTransaction.commit() 不合适。

flush() 必须包含在事务上下文中,除非需要(在极少数情况下),当 EntityTransaction.commit() 为您执行此操作时,您不必显式执行此操作。

参考此链接Is it necessary to call a flush() (JPA interface) in this situation?

参考此链接Question about flushing with JPA before a query is called 了解使用flush() 的场景

【讨论】:

正如我问 DataNucleus:我可以用 flush() 做什么而我不能不使用它? 更新了我的答案。希望该链接回答您的问题。 @AhamedMustafaM Both of your code samples doesn't persist or merge the entity state to be written to DB 否,如果实体是托管的,则更改将隐式同步到数据库中。 @NayanWadekar 感谢您提供新信息。让我分析并删除它【参考方案4】:

我会尽可能使用容器管理事务。由于异常的可能性,Bean 管理的事务通常需要更多的代码。此外,它更容易出错(回滚、资源管理)。

也就是说,我会在容器管理模式下提交后使用刷新。这样我就可以在我的存储模块中捕获可能的 PersistenceExceptions 并将其转换为对我的用例模块更有意义的异常。这是因为我不想在这里处理特定于存储的异常,因为我可能会将存储模块换成不使用 JPA 的东西......这从未发生在我身上:)

【讨论】:

【参考方案5】:

我认为缺少的部分是,flush() 只是添加到数据源以准备提交,提供实际 id,但默认情况下不持久。

因此,如果您需要flush() 作为commit() 工作,您需要在EntityManager 中通过以下方式将flush 模式设置为Commit:

void setFlushMode(FlushModeType flushMode)
Set the flush mode that applies to all objects contained in the persistence context.

请注意,FlushModeType 是一个具有以下两个值的枚举:

FlushModeType AUTO(默认)在查询执行时进行刷新。 自:JPA 1.0 FlushModeType COMMIT 刷新发生在事务 犯罪。提供程序可能会在其他时间刷新,但不是必须的。 自:JPA 1.0

希望对你有帮助

【讨论】:

以上是关于Entitymanager.flush() VS EntityManager.getTransaction().commit - 我应该更喜欢啥?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何让 JPA EntityManager Flush 工作

Java世界中的类vs包vs模块vs组件vs容器vs服务vs平台[关闭]

VS2005和VS2008做的项目有啥区别

性能测试 - 响应 vs 延迟 vs 吞吐量 vs 负载 vs 扩展性 vs 压力 vs 健壮性

VS2010怎样打开VS2013或者VS2015建立的工程

Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012