2016-08-27 38 views
1

我在Spring + Hibernate + SQLite堆棧中遇到了回滾失敗事務的問題。Spring + Hibernate + SQLite事務怪異

這裏是我的榜樣

查看方法TestBean.testMethod()

public void testMethod() { 
    entityManager.persist(createOrder("1")); 
    entityManager.persist(createOrder("2")); 
    entityManager.persist(createOrder("3")); 
    entityManager.createQuery("from Order").getResultList(); 
    entityManager.persist(createOrder("4")); 
    throw new RuntimeException("Managed"); 
} 

它創建並保留了一些Order實體。 它在一些創建之間從數據庫讀取一些數據。 最後,它拋出RuntimeException來模擬方法調用期間的失敗並強制Spring回滾事務。

執行完後,我打開數據庫,看到它只是最後一個創建的實體(createOrder(「4」))和所有其他的(名稱爲「1」,「2」和「3」)數據庫。但是由於TestBean被標記爲@Transactional,它應該刪除在一個事務性方法testMethod()中創建的所有四個實體。

我嘗試了SQLIte中的所有journal_mode,但回滾仍然不起作用。

任何想法?

+0

看來,每個** em.persist()**調用Hibernate調用** JdbcIsolationDelegate#delegateWork **。與此同時,方法** JdbcIsolationDelegate#delegateWork **調用** Connection#commit **,它在JPA/Hibernate框架中斷開所有事務交互 – Joltd

回答

0

經過很長時間我發現問題的真正原因 - 它是應用程序中所有實體的註釋的戰略類型@GeneratedValue

默認情況下,註釋提供的策略是AUTO,這意味着Hibernate將在目標數據庫(hibernate_sequence)中使用自己的表來生成ID值。 Hibernate在單獨的事務中調用查詢(從hibernate_sequence中選擇當前值) - 在這一點上我們遇到了這個問題。

如果您使用通用多連接數據源而不是Hibernate嘗試獲取新連接,但SQLite只能有一個活動連接 - 我們獲得「數據庫文件被鎖定」錯誤。 如果您使用防止連接關閉的Spring的SingleConnectionDataSource,那麼Hibernate將重新使用現有連接,但會創建新的單獨事務。新的交易將成功完成,但要求新ID的舊交易將失敗。

所以解決的方法很簡單,只要確保所有您的實體註釋像

@GeneratedValue(strategy = GenerationType.IDENTITY) 

因此,在這種情況下,Hibernate會委派ID值的生成的基礎數據庫。

相關問題