背景:
项目对转账的功能进行优化,测试的时候,发现原转账功能无法使用。
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连接来处理。
总结:
出现该问题的时候,肯定是有其它地方占用了锁,问题的解决点:需要先释放锁或者报错所有的操作,在同一个事物中。