java.sql.SQLException: connection holder is null;


一、問題來源分析

出現的錯誤 :

Cause: java.sql.SQLException: connection holder is null; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; connection holder is null; nested exception is java.sql.SQLException: connection holder is null

1.出現的原因,數據庫鏈接丟失,出現的原因是這樣的,我需要執行定時任務去定時更新數據庫的數據,每次分頁循環跟新,開始數據不多,能成功,后來數據量大了,到了下一次任務開始也不能結束,但是數據庫已經報錯了,報錯理解起來也很簡單,數據連接丟失,一開始問了度娘,修改了一下的參數

<!-- 1800秒,也就是30分鍾 修改為了36000,即10小時-->     
<property name="removeAbandonedTimeout" value="36000" />

以為問題解決了,到但是過幾天還是報錯了,仔細想了下,業務代碼得改啊,不然的話,連接肯定會超時的,於是修改了業務代碼,采用了多線程,每次獲取數據庫的少於設置的removeAbandonedTimeout的時間即可以成功,功能算是可以了;

二、問題的思考

近段時間學習了mysql,對這個問題沖新思考了下

  1. 首先來說下數據的長連接和短連接:

    短連接:短連接則是指每次執行完很少的幾次查詢就斷開連接,下次查詢再重新建立一個;

    長連接:長連接是指連接成功后,如果客戶端持續有請求,則一直使用同一個連接;

    建立連接的過程是比較復雜的,也就有了數據庫連接池的出現,但是,我理解為每次從連接池中獲取到一個數據庫連接,然后不停的執行業務代碼,也相當於一個長連接;我的問題就應該是這樣出現的。

  2. 如果除開數據源,是建議多使用長連接的,可以減少建立數據庫鏈接的開銷的,但是全部使用長連接后,你可能會發現,有些時候 MySQL 占用內存漲得特別快,這是因為 MySQL 在執行過程中臨時使用的內存是管理在連接對象里面的。這些資源會在連接斷開的時候才釋放。所以如果長連接累積下來,可能導致內存占用太大,被系統強行殺掉(OOM),從現象看就是 MySQL 異常重啟了。

  3. 后面去看定時任務日志的時候,定時任務每次沒執行完成,就報錯了;客戶端如果太長時間沒動靜,連接器就會自動將它斷開。這個時間是由參數 wait_timeout 控制的,默認值是 8 小時,及就算采用了數據庫鏈接池,鏈接的時間過長,也會被數據庫斷開;

三、 問題拓展優化

上面我所說的業務的關聯性不是很大,如果業務要求有前后的關聯關系,而且時間又比較長,該怎么半呢?

  • 定期斷開長連接。使用一段時間,或者程序里面判斷執行過一個占用內存的大查詢后,斷開連接,之后要查詢再重連

  • 如果你用的是 MySQL 5.7 或更新版本,可以在每次執行一個比較大的操作后,通過執行 mysql_reset_connection 來重新初始化連接資源。這個過程不需要重連和重新做權限驗證,但是會將連接恢復到剛剛創建完時的狀態。

    第一個方案比較好理解,第二個方案就很只能針對高版本的mysql了,不過這樣就比較好解決上面出現的問題了;


免責聲明!

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



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