環境:
持久層:JPA
數據庫連接池:druid
數據庫中間件:Mycat
數據庫:Mysql
報錯:
Unable to acquire JDBC Connection
排查步驟:
方法一:
1、druid配置沒有問題。
2、Mysql連接數正常,但是發現mysql有很多鏈接沒有釋放。(用root用戶執行:show full processlist ; 指令)
如圖:發現很多State = Sleep的鏈接,鏈接都很長,一直不釋放鏈接。
3、kill掉相應的鏈接。(因為業務數據不是很重要,為了先恢復功能,用此下策)
4、接着排查代碼。發現JPA的save方法,默認更新一條記錄使用如下方式:update tb_name set xxx = xxx where id = xxx ; 使用默認的主鍵進行數據的更新。而業務側,由於數據龐大使用了數據庫的分庫分表,mycat作為數據庫中間件,該表的路由規則為:根據用戶id去摸,進行數據的分庫分表。
問題原因找到:每次執行更新(save)方法時,Mycat都會廣播這條sql,當數在插入時,就造成更新方法阻塞等待(鎖,事務相關),導致鏈接不釋放。
方法二:
1、查看mysql事務表,得到thread_id : select * from information_schema.INNODB_TRX ; 從結果中的:trx_mysql_thread_id 得到線程id
2、select * from performance_schema.threads where THREAD_ID = 第一步得到的線程id (這一步可以不執行,目的只是為了演示mysql的線程管理,以及相應的查看方法。)
3、select * from performance_schema.events_statements_current where THREAD_ID = 第一步得到的線程id ; 根據 SQL_TEXT 得到相應的sql語句。
以上就是mysql通過阻塞的線程,找到代碼中相應的sql的方法。
解決方法:
1、寫sql,在更新數據時,修改JPA默認的方式,使用路由規則去更新數據。