从实体管理器提交不包含任何脏对象的事务时会发生什么?是不是没有向DB发送COMMIT命令?
我现在有一些测试用例失败但没有合理的原因。经过一番调查,我现在有一个理论,我想在这里得到证实。
我有一个小夹具框架,用于为每个测试准备DB上的数据。灯具使用这种方法使用JPA(Hibernate)将对象存储到DB:
public <R> R doInTransaction(final Function<EntityManager, R> whatToDo) {
final EntityManager em = emf.createEntityManager();
final R result;
try {
try {
em.getTransaction().begin();
result = whatToDo.apply(em);
em.getTransaction().commit();
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
} finally {
em.close();
}
return result;
}
因此,fixture调用此方法传递whatToDo函数,其中对象被持久化,并且该方法围绕传递的函数包装事务。我失败的测试用例使用的是一个依赖于使用存储过程的遗留代码并通过JDBC直接存储对象的fixture,i。即而不是使用em.persist()
,我在传递的函数中使用以下内容来调用存储过程:
em.unwrap(Session.class).doWork(connection -> {
// stored procedures are called here directly over JDBC
});
所以,我的理论是JPA在这种情况下没有立即提交,因为没有EntityManager管理的JPA脏对象。因此,实际提交仅在稍后发生,即。即在我的测试断言后,测试失败了。可能是吗?
当&#34;展开&#34;时,Hibernate的事务行为是什么? EntityManager的连接?
我现在在em.flush()
之前添加em.getTransaction().commit()
并且它似乎有所帮助,但我仍然没有100%确信这可以解决问题。有人可以证实吗?
答案 0 :(得分:0)
无论是否打开连接,行为都是相同的。如果您不使用JTA,则替代方案是JDBC提供的基础事务,即本地事务。 (或者您可以实现自己的托管交易提供程序)
当您打开连接并直接处理JDBC时,您仍然可以获得此会话/实体管理器最初获得的相同连接。所以它的效果相同。