背景:
項目對轉賬的功能進行優化,測試的時候,發現原轉賬功能無法使用。
mysql報錯:
Statement cancelled due to timeout or client request
問題分析:
從字面意思來看是,預編譯在等待執行或執行的時候,因爲超時而取消了。
那麼什麼原因呢?
1.語句執行過慢
解決:
a.加索引
b.子查詢儘量縮小搜索範圍,減少join的次數
c.能用join就不要用in
d.加大查詢時間 queryTimeOut
我們這邊加大了queryTimeOut時間,然後報錯:Lock wait timeout exceeded; try restarting transaction
通過排查,發現是在執行更新操作的時候,一直在等待鎖。
select * from information_schema.innodb_trx;
select * from information_schema.innodb_locks;
select * from information_schema.INNODB_LOCK_WAITS;
SELECT * from information_schema.`PROCESSLIST`;
SHOW FULL PROCESSLIST;
當發現一直在佔用鎖的事物鎖,kill掉。
kill id
排查發現:佔用的鎖的語句,就是正在執行的更新語句。 這個是不對的。
繼續排查,發現方法中使用了事物,該事務綁定的是sql連接池。
執行順序是:
事物開始:
操作A進行了該行語句的更新
操作B(我的語句)執行該行語句的更新(該操作是自己建立的sql連接對象操作)
事物結束
這個時候,大家都發現問題了吧。
操作B必須要等到操作A事物提交,才能拿到行級鎖。
修改:
方案1:
將操作B也使用sql連接池的連接,進行數據庫操作
方案2:
將操作A進行修改,改成使用自己建立的sql連接來處理。
總結:
出現該問題的時候,肯定是有其它地方佔用了鎖,問題的解決點:需要先釋放鎖或者報錯所有的操作,在同一個事物中。