Spring編程式事務使用不當導致其他事務無法正常提交


1.事故背景

原本在使用的是注解式事務,后面因為需要在事務中增加異步推送機制,所以需要將推送機制放到事務之外,修改后發現系統經常出現事務長時間無法提交導致回滾。

2.排查流程

(1)一開始重啟應用是能恢復正常,所以肯定是在某種情況下會觸發異常的產生

(2)查看在mysql控制台查看當前正在執行的事務(SELECT * FROM information_schema.INNODB_TRX),分析該sql語句在邏輯上並沒有鎖競爭的出現,只是單單一條update語句,但事務卻沒有提交

(3)這時候確定在業務代碼邏輯上不會出現鎖競爭,但事務卻沒有正常提交,所以考慮是mysql連接會話的autoCommit屬性為false導致事務無法正常提交

(4)因異常出現是在講注解式事務改為編程式事務之后,所以猜測是因為該改動導致異常出現

3.原理分析

(1)spring事務支持原理:spring的事務支持原理是先將mysql連接會話的自動提交屬性關閉,即將當前會話的autoCommit屬性設置為false,然后將該連接綁定到該線程中,在該事務中的所有數據庫操作都是使用同一個線程,所有的數據庫操作完成后才主動去做commit操作完成事務

(2)以下為編程式事務出現異常的流程分析的代碼示例

當開啟事務時,當前會話的自動提交屬性講被設置為false

 當事務沒有提交而是提前return出去時,會話的狀態並不會改變,autoCommit屬性一直為false,這就導致當其他請求使用該數據庫連接會話操作數據庫時,事務將無法自動提交,如下圖所示,即使沒有開啟事務,

autoCommit狀態也是為false,所以會導致其他使用該會話的事務無法正常提交

 

 

 4.改進方式

(1)避免在未主動commit事務前return出去

(2)增加finally代碼塊,判斷事務狀態,回滾事務即可

DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
        try {
           doSomething();
        } catch (Exception e) {
            transactionManager.rollback(transactionStatus);
            getLogger().error(e.getMessage());
            throw new RuntimeException("系統異常");
        } finally {
            if(null != transactionStatus && !transactionStatus.isCompleted()){
                transactionManager.rollback(transactionStatus);
            }
        }

 連接恢復源碼如下:

 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM