我想解決的底層問題是運行一個任務,它會在MySQL中生成幾個臨時表,這些臨時表需要足夠長的時間才能在Java創建後從Java中獲取結果。由於涉及的數據量很大,任務必須分批完成。每批都是對通過JDBC調用的存儲過程的調用。對於大型數據集,整個過程可能需要半小時或更長時間。與Spring和Hibernate長時間運行事務?
爲了確保訪問臨時表,我使用TransactionCallbackWithoutResult在一個Spring事務中運行整個任務,從頭到尾。否則,我可能會得到一個不能訪問臨時表的不同連接(在將事務包裝在事務中之前偶爾會發生這種情況)。
這在我的開發環境中工作得很好。然而,在生產中我得到了以下異常:
java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
這種情況發生時,不同的任務已經盡了長期運行的事務的執行過程中訪問一些相同的表。令我困惑的是,長時間運行的事務只能插入或更新到臨時表中。所有對非臨時表的訪問都是隻能選擇的。從我能找到的文檔中,默認的Spring事務隔離級別不應該導致MySQL在這種情況下阻塞。
所以我的第一個問題,這是正確的方法?我可以確保我通過Hibernate模板重複獲得相同的連接而無需長時間運行事務嗎?
如果長時間運行的事務方法是正確的,我應該在隔離級別方面檢查什麼?我的理解是否正確:Spring/MySQL事務中的默認隔離級別不應鎖定僅通過選擇來訪問的表?我能做些什麼來調試哪些表導致衝突,並防止這些表被事務鎖定?
你有解決「維護連接」問題嗎?在我的情況下,Spring和Hibernate調解我與數據庫的連接,並且每次都無法獲得相同的連接,而無需將所有內容都包裝在單個事務中。如果沒有維護相同的連接,我將無法訪問臨時表。 – jimbokun 2010-06-02 15:37:48
如果您保留帶有ID的工作日誌並在批處理中達到里程碑,則可以創建名爲TEMP_ _STUFF的常規表。根據達成的里程碑,您可以跳過並繼續中止批處理。處理完成後(即到達里程碑DONE),移除表格並記錄到達「已清潔」的里程碑。現在所有的處理都可以通過細粒度的事務來完成。這種方法不方便的是,當批處理作業開始時,您看不到數據庫狀態的「快照」。這可能是也可能不是問題。 –
2010-06-02 16:05:21
這是非常好的建議。然而,我還有一個問題。一些初始處理會創建臨時表,這些臨時表可在每批中訪問。這個初始處理需要大量的時間,如果必須對每個批次重複進行處理,這足以造成顯着的性能下降。 我不知道如何處理這個初始處理,但我會給它一些更多的想法。 – jimbokun 2010-06-02 17:15:42