首页 > 数据库 >Mysql 异常:MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

Mysql 异常:MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

时间:2022-10-13 18:04:59浏览次数:74  
标签:MySQLTransactionRollbackException 事务 transaction Lock trx innodb timeout mysql i

问题现象

接口响应时间超长,耗时几十秒才返回错误提示,后台日志中出现Lock wait timeout exceeded; try restarting transaction的错误

### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

问题场景

  • 1、在同一事务内先后对同一条数据进行插入和更新操作;

  • 2、分布式服务操作同一条记录;

  • 3、瞬时出现高并发现象;

问题原因

  • 1、在高并发的情况下,Spring事物造成数据库死锁,后续操作超时抛出异常。

  • 2、Mysql数据库采用InnoDB模式,默认参数:innodb_lock_wait_timeout设置锁等待的时间是50s,一旦数据库锁超过这个时间就会报错。

解决方法

方法一:调整超时参数

mysql官方文档如下:

当锁等待超时后innodb引擎报此错误,等待时间过长的语句被回滚(不是整个事务)。如果想让SQL语句等待其他事务更长时间之后完成,你可以增加参数innodb_lock_wait_timeout配置的值。如果有太多长时间运行的有锁的事务,你可以减小这个innodb_lock_wait_timeout的值,在特别繁忙的系统,你可以减小并发。 InnoDB事务等待一个行级锁的时间最长时间(单位是秒),超过这个时间就会放弃。默认值是50秒。一个事务A试图访问一行数据,但是这行数据正在被另一个innodb事务B锁定,此时事务A就会等待事务B释放锁,等待超过innodb_lock_wait_timeout设置的值就会报错ERROR 1205 (HY000):

innodb_lock_wait_timeout是动态参数,默认值50秒,最小值是1秒,最大值是1073741824;

set innodb_lock_wait_timeout=1500等价于set session只影响当前sessio。set global innodb_lock_wait_timeout=1500作为全局的修改方式,只会影响修改之后打开的session,不能改变当前session。

mysql> set GLOBAL innodb_lock_wait_timeout=1500;

方法二:解决死锁

1、查看数据库当前的进程

show processlist会显示出当前正在执行的sql语句列表,找到消耗资源最大的那条语句对应的id.

mysql> show processlist; 
+---------+------+-------------------+--------------------+---------+-------+-------+------------------+
| Id      | User | Host              | db                 | Command | Time  | State | Info             |
+---------+------+-------------------+--------------------+---------+-------+-------+------------------+
| 3205081 | root | 172.19.2.8:50317  | ********           | Sleep   | 16485 |       | NULL             |
| 3210354 | root | 172.19.2.8:51066  | information_schema | Sleep   |  3569 |       | NULL             |
| 3210630 | root | 172.19.2.12:61845 | ********           | Query   |     0 | init  | show processlist |
+---------+------+-------------------+--------------------+---------+-------+-------+------------------+
10 rows in set (0.00 sec)

2、查看当前的锁和事务

在5.5中,information_schema 库中增加了三个关于锁的表(inndodb引擎):

  • innodb_trx ## 当前运行的所有事务
  • innodb_locks ## 当前出现的锁,查看正在锁的事务
  • innodb_lock_waits ## 锁等待的对应关系 ,查看等待锁的事务

当前运行的所有事务

mysql> SELECT * FROM information_schema.INNODB_TRX;

当前出现的锁

mysql> SELECT * FROM information_schema.INNODB_LOCKs;

锁等待的对应关系

mysql> SELECT * FROM information_schema.INNODB_LOCK_waits;

看里面是否有正在锁定的事务线程,看看ID是否在show processlist里面的sleep线程中,如果是,就证明这个sleep的线程事务一直没有commit或者rollback而是卡住了

3、查询产生锁的具体sql

根据具体的sql,就能看出是不是死锁了,并且可以确定具体是执行了什么业务,是否可以kill;

select 
    a.trx_id 事务id ,
    a.trx_mysql_thread_id 事务线程id,
    a.trx_query 事务sql 
from 
    INFORMATION_SCHEMA.INNODB_LOCKS b,
    INFORMATION_SCHEMA.innodb_trx a 
where 
    b.lock_trx_id=a.trx_id;

4、杀掉死锁的事务

查询出所有有锁的事务对应的线程ID(注意是线程id,不是事务id),通过information_schema.processlist表中的连接信息生成需要处理掉的MySQL连接的语句临时文件,然后执行临时文件中生成的指令。

mysql> select concat('KILL ',a.trx_mysql_thread_id ,';') from INFORMATION_SCHEMA.INNODB_LOCKS b,INFORMATION_SCHEMA.innodb_trx a where b.lock_trx_id=a.trx_id;
+------------------------+
| concat('KILL ',id,';') |
+------------------------+
| KILL 3205081;            |
| KILL 3210354;            |
| KILL 3210630;            |
+------------------------+
18 rows in set (0.00 sec)

如果太多的话可以导出到txt再批量执行

mysql> select concat('KILL ',a.trx_mysql_thread_id ,';') from INFORMATION_SCHEMA.INNODB_LOCKS b,INFORMATION_SCHEMA.innodb_trx a where b.lock_trx_id=a.trx_id into outfile '/tmp/kill.txt';

KILL命令允许自选的CONNECTION或QUERY修改符:KILL CONNECTION与不含修改符的KILL一样:它会终止与给定的thread_id有关的连接。KILL QUERY会终止连接当前正在执行的语句,但是会保持连接的原状。KILL命令的语法格式如下:

KILL [CONNECTION | QUERY] thread_id

运行kill命令

mysql> kill 3205081;
Query OK, 0 rows affected (0.00 sec)
 
mysql> kill 3210354;
Query OK, 0 rows affected (0.00 sec)

总结

Mysql造成锁的情况有很多,以下列了4种情况:

  • 执行DML操作没有commit,再执行删除操作就会锁表;
  • 在同一事务内先后对同一条数据进行插入和更新操作;
  • 表索引设计不当,导致数据库出现死锁;
  • 长事物,阻塞DDL,继而阻塞所有同表的后续操作。

出现事务锁表等待,解决的办法有四种:

  • 1、找出出现锁表的事务进程杀死;
  • 2、进行sql语句分析,优化慢sql;
  • 3、把事务等待时间延长;
  • 4、修改表的存储引擎为innodb。

参考: https://blog.csdn.net/weixin_38004638/article/details/112789026

https://blog.csdn.net/luoyeyeyu/article/details/103118318

https://www.cnblogs.com/jasonboren/p/13711372.html

标签:MySQLTransactionRollbackException,事务,transaction,Lock,trx,innodb,timeout,mysql,i
From: https://blog.51cto.com/u_14014612/5754473

相关文章

  • package.json 与 package-lock.json 的关系
    模块化开发在前端越来越流行,使用node和npm可以很方便的下载管理项目所需的依赖模块。package.json用来描述项目及项目所依赖的模块信息。那 package-lock.json 和......
  • Luogu P3469 [POI2008]BLO-Blockade
    [P3469POI2008]BLO-Blockade-洛谷|计算机科学教育新生态(luogu.com.cn)图\(G\)本身联通。删除\(u\)的连边后会形成\(k\ge2\)个连通块(至少会把\(u\)隔离出......
  • PriorityBlockingQueue详解
    PriorityBlockingQueue介绍【1】PriorityBlockingQueue是一个无界的基于数组的优先级阻塞队列,数组的默认长度是11,也可以指定数组的长度,且可以无限的扩充,直到资源消耗......
  • 重入锁ReentrantLock
    1.重入锁和synchronized比较特征synchronizedreentrantLock底层原理JVM实现JDK实现性能区别低->高(JDK5+)高锁的释放自动释放(编译器保证)手动释放(finall......
  • Unlock Object list:CR下清单解锁
    有时候挂错了地方乱七八糟的情况都有有时候需要传输的时候,挂了一堆乱七八糟的对象等等。会发现对象被锁,需要解锁SE10​......
  • Single Transaction Analysis (ST12) getting started
     heSingleTransactionAnalysiswasdeveloped topromotetheusageofABAPtraceinsideSAPSupport.ItintegratestheABAP-(SE30)andthePerformance(ST05)......
  • 在 win10 上如何把 capslock 映射到 esc 上?
    参考网址:https://www.makeuseof.com/windows-10-11-disable-caps-lock/(HowtoDisableCapsLockbyEditingtheRegistry看第八)"ScancodeMap"=hex:00,00,00,00,00,......
  • StampedLock:一个并发编程中非常重要的票据锁
    摘要:一起来聊聊这个在高并发环境下比ReadWriteLock更快的锁——StampedLock。本文分享自华为云社区《【高并发】一文彻底理解并发编程中非常重要的票据锁——StampedLock......
  • Unlock Object list:CR下清单解
    有时候挂错了地方乱七八糟的情况都有有时候需要传输的时候,挂了一堆乱七八糟的对象等等。会发现对象被锁,需要解锁SE10​......
  • LinkedBlockingDeque详解
    LinkedBlockingDeque介绍【1】LinkedBlockingDeque是一个基于链表实现的双向阻塞队列,默认情况下,该阻塞队列的大小为Integer.MAX_VALUE,可以看做无界队列,但也可以设置容......