2010-06-02 21 views
5

我想解決的底層問題是運行一個任務,它會在MySQL中生成幾個臨時表,這些臨時表需要足夠長的時間才能在Java創建後從Java中獲取結果。由於涉及的數據量很大,任務必須分批完成。每批都是對通過JDBC調用的存儲過程的調用。對於大型數據集,整個過程可能需要半小時或更長時間。與Spring和Hibernate長時間運行事務?

爲了確保訪問臨時表,我使用TransactionCallbackWithoutResult在一個Spring事務中運行整個任務,從頭到尾。否則,我可能會得到一個不能訪問臨時表的不同連接(在將事務包裝在事務中之前偶爾會發生這種情況)。

這在我的開發環境中工作得很好。然而,在生產中我得到了以下異常:

java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction 

這種情況發生時,不同的任務已經盡了長期運行的事務的執行過程中訪問一些相同的表。令我困惑的是,長時間運行的事務只能插入或更新到臨時表中。所有對非臨時表的訪問都是隻能選擇的。從我能找到的文檔中,默認的Spring事務隔離級別不應該導致MySQL在這種情況下阻塞。

所以我的第一個問題,這是正確的方法?我可以確保我通過Hibernate模板重複獲得相同的連接而無需長時間運行事務嗎?

如果長時間運行的事務方法是正確的,我應該在隔離級別方面檢查什麼?我的理解是否正確:Spring/MySQL事務中的默認隔離級別不應鎖定僅通過選擇來訪問的表?我能做些什麼來調試哪些表導致衝突,並防止這些表被事務鎖定?

回答

1

當你說你的表是臨時的,它是交易範圍?這可能會導致其他交易(可能在不同的交易中)無法看到/訪問它。也許涉及真實表和臨時表的連接以某種方式鎖定了真正的表。

根本原因:您是否嘗試過使用MySQL工具來確定什麼是鎖定連接?這可能是像下一行鎖定。我不太瞭解MySQL工具,但在oracle上,您可以看到哪些連接阻塞了其他連接。

事務超時:您應該創建第二個連接池/數據源,其超時時間要長得多。爲長時間運行的任務使用該連接池。我認爲你的生產環境試圖通過檢測卡住的連接來幫助你。

6

我認爲保持交易對於長時間的邪惡是敞開的。在我的職業生涯中,「擴展」的定義從幾秒到幾秒。

這是一個不可重複的問題和headscratching問題的無休止來源。

在這種情況下,我會咬緊牙關,並在軟件中保留一份「工作日誌」,如果批處理失敗,您可以反向重新進行清理。

+0

你有解決「維護連接」問題嗎?在我的情況下,Spring和Hibernate調解我與數據庫的連接,並且每次都無法獲得相同的連接,而無需將所有內容都包裝在單個事務中。如果沒有維護相同的連接,我將無法訪問臨時表。 – jimbokun 2010-06-02 15:37:48

+0

如果您保留帶有ID的工作日誌並在批處理中達到里程碑,則可以創建名爲TEMP_ _STUFF的常規表。根據達成的里程碑,您可以跳過並繼續中止批處理。處理完成後(即到達里程碑DONE),移除表格並記錄到達「已清潔」的里程碑。現在所有的處理都可以通過細粒度的事務來完成。這種方法不方便的是,當批處理作業開始時,您看不到數據庫狀態的「快照」。這可能是也可能不是問題。 – 2010-06-02 16:05:21

+0

這是非常好的建議。然而,我還有一個問題。一些初始處理會創建臨時表,這些臨時表可在每批中訪問。這個初始處理需要大量的時間,如果必須對每個批次重複進行處理,這足以造成顯着的性能下降。 我不知道如何處理這個初始處理,但我會給它一些更多的想法。 – jimbokun 2010-06-02 17:15:42

0

就像Justin提到的有關事務超時一樣,我最近遇到連接池(在我的例子中Tomcat 7中的tomcat dbcp)設置了應該標記長連接的標記的問題,放棄並關閉它們。調整這些參數後,我可以避免這個問題。