從不包含任何髒對象的實體管理器提交事務時會發生什麼?是否沒有COMMIT命令發送到數據庫?JPA提交由解包連接完成的更改
我有一些測試用例失敗,然後沒有合理的原因。經過一番調查後,我現在有一個理論,我想在這裏證實。
我有一個小夾具框架來準備每個測試數據庫的數據。燈具用這樣的方法將對象存儲到使用JPA(休眠)的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;
}
因此,夾具調用此方法傳遞whatToDo功能,而對象仍和方法周圍的傳遞函數包裝了一個交易。我失敗的測試用例正在使用依賴於使用存儲過程的遺留代碼的fixture,並通過JDBC直接存儲對象。即而是採用em.persist()
,我用下面的傳遞函數來調用存儲過程:
em.unwrap(Session.class).doWork(connection -> {
// stored procedures are called here directly over JDBC
});
所以,我的理論是,JPA在這種情況下也不會立即提交,因爲有由管理沒有JPA髒對象EntityManager的。因此,實際的提交只會在晚些時候發生。即在我的測試聲明和測試失敗後。它會是嗎?
當「解開」連接到EntityManager之外時,Hibernate的事務行爲是什麼?
我已經在em.getTransaction().commit()
之前添加了一個em.flush()
,它似乎有所幫助,但我仍然不是百分之百相信這可以解決問題。有人可以證實嗎?
混合和匹配持久處理程序時,您必須小心。 Hibernate維護一個什麼是髒的緩存,什麼不是。如果你在hibernate以外的地方更新東西,那麼hibernate有可能會與db不同步並刪除更新,因爲它認爲它的實體的緩存版本仍然有效。過去幾年我經常遇到類似這樣的問題,如果我沒有記錯的話,我們在hibernate中禁用緩存以防止這種行爲。 – Stephan
我不喜歡在Hibernate中進入緩存的神祕世界...... :)如果'em.flush()'在這裏完成這項工作,這對我來說已經足夠了。 – Alex
如果你在測試環境中,可以隨時嘗試em.flush()並查看。就緩存設置而言,如果您不希望有太多併發用戶,您應該能夠在hibernate中禁用緩存,並讓數據庫中的緩存處理大部分工作。這是另一回事,數據庫的默認緩存會干擾休眠的默認緩存。如果您繼續遇到問題,我強烈建議關閉休眠緩存。 – Stephan