一、报错现象
org.springframework.dao.CannotAcquireLockException:
### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
这个错误是由于有线程或者是有其他操作在频繁的操作mysql数据库导致表被锁了。
二、原因
1、Spring事务嵌套,当前的业务方法中在一个事务中执行,但是这个方法里还存在调用其他方法,可能也加了事务,底层报错时,事务回滚造成死锁
A,B两个方法开启事务 ,
A的传播级别为默认REQUIRED(当前有事务则加入,没有则创建),
B的传播级别为NOT_SUPPORTED (当前有事务则挂起,以非事务方式执行)
A新增/更新数据 ,B更新同条数据,然后会发生事务死锁
原因分析 : A开启事务,新增/更新数据时会锁住数据,之后执行B方法,B不支持事务会暂停A的事务,A事务还未提交就被暂停,数据加锁,B又去更新数据(此时无法更新一直等待锁的释放,陷入死锁)
2、查询性能太慢,数据库压力太大,对象被锁定,导致事务出现问题。
三、解决方式
1、排查对应方法使用的事务传播性为以及使用了事务的方法之间的调用是否合理。
2、如果是查询性能太慢,那就需要优化查询sql了,通过explain分析查询语句,查看是否命中索引。sql的type是否达到ref级别以上,如果是range级别,说明未能命中所有索引。
3、本次出现这个问题是由于,测试环境中有测试同学进行性能压测,然后关联到了这张表,导致对这种表出现频繁操作,以至于数据库压力增大而锁表。
在数据库中执行下面语句。
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
会出现
2、然后找到 trx_mysql_thread_id 列
使用kill id;删除掉对应线程id即可解决。