1. 程式人生 > >坑爹的Spring資料來源——自動提交事務

坑爹的Spring資料來源——自動提交事務

問題描述

專案中涉及充值、扣費邏輯,由於習慣,所以所有的業務邏輯都是通過Mysql儲存過程來控制的,所以很自然的將Mysql設定為手動提交(全域性的),然後儲存過程中根據返回碼決定是提交還是回滾。但是今天出現一個儲存過程返回錯誤碼,但是部分事務提交了,研究了半天,發現並沒有任務問題,手動呼叫儲存過程是返回錯誤碼,但是不會部分提交事務。於是決定找下問題,不找不知道,一找嚇一跳。

(先說明下,專案未使用Spring的事務管理,而是通過儲存過程手動控制事務,所以此處與Spring的事務管理無任何關係。)

由於經過測試排除了資料庫層面的問題,那麼問題只能出現在程式層了。

問題發現

專案使用的Spring配置的JBoss的JNDI資料來源,JBoss也比較老(是很老),通過使用Spring執行select @@autocommit;發現autocommit竟然是1(自動提交事務),但是明明已經在資料庫層將autocommit設定為0(手動提交事務)了,很顯然Connection中主動設定了當前會話的autocommit。

問題深究

由於Connection來自DataSource,而Spring中對Connection並未做任何的封裝,同時通過Debug發現Spring獲得的Connection是org.jboss.resource.adapter.jdbc.WrappedConnection類,看來是JBoss的JNDI資料來源的Connection沒錯了。沒找到原始碼,所以只好用jd反編輯查看了,發現裡面有個jdbcAutoCommit,預設是true,WrappedConnection是實現java.sql.Connection的,所以提供了setAutoCommit(),但是由於能力有限無法找到JBoss初始化JNDI資料來源的程式碼,也沒找到任何可配置該引數的地方,所以沒整了。

問題解決

既然寫這篇文章,總歸有個解決方案,不管好還是不好,總不能留著打自己臉呀。

解決方案就是發現JBoss配置資料來源時有一個引數:new-connection-sql,通過註釋發現該引數是在每次建立一個新的Connection時呼叫的,目的可能是用來測試或者其他的,有了這個引數我們就可以在所有通過該Connection的請求之前設定當前Connection的autoCommit=0,所以這個引數的值設定為set autocommit=0就可以解決啦。

同時發現有些資料來源頁不提供自動提交事務配置,預設還都是true(不知道是自己沒找對還是真的沒有,如C3P0)。

以上所述當然是簡單敘述,實際過程複雜坎坷,不宜觀看。