MySQL事务锁问题-Lock wait timeout exceeded

本文探讨了接口响应超长的常见问题,聚焦于高并发下Spring事务引发的数据库死锁。通过分析事务表、锁等待关系和慢SQL,提供了逐步排查和解决的方法,包括检查事务状态、强制提交和调整InnoDB锁等待时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题现象

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

二、问题场景

  1. 在同一事务内先后对同一条数据进行插入和更新操作;
  2. 多台服务器操作同一数据库;
  3. 瞬时出现高并发现象;

三、问题原因

  1. 在高并发的情况下,Spring事务造成数据库死锁,后续操作超时抛出异常。
  2. MySQL数据库采用InnoDB模式,默认参数innodb_lock_wait_timeout设置锁等待的时间是50s,一旦数据库锁超过这个时间就会报错。

四、解决方法

  1. 查看数据库当前的进程,看一下有无正在执行的慢SQL记录线程。

mysql> show processlist;

  1. 查看当前的事务

当前运行的所有事务:
mysql> SELECT * FROM information_schema.INNODB_TRX;

当前出现的锁:
mysql> SELECT * FROM information_schema.INNODB_LOCKs;

锁等待的对应关系:
mysql> SELECT * FROM information_schema.INNODB_LOCK_waits;

解释:看事务表INNODB_TRX,里面是否有正在锁定的事务线程,看看ID是否在show processlist里面的sleep线程中,如果是,就证明这个sleep的线程事务一直没有commit或者rollback而是卡住了,我们需要手动kill掉。

搜索的结果是在事务表发现了很多任务,这时候最好都kill掉。

  1. 批量删除事务表中的事务

这里用的方法是:通过information_schema.processlist表中的连接信息生成需要处理掉的MySQL连接的语句临时文件,然后执行临时文件中生成的指令。

mysql> select concat(‘KILL ‘,id,’;’) from information_schema.processlist where user=‘cms_bokong’;
±-----------------------+
| concat(‘KILL ‘,id,’;’) |
±-----------------------+
| KILL 10508; |
| KILL 10521; |
| KILL 10297; |
±-----------------------+
18 rows in set (0.00 sec)

当然结果不可能只有3个,这里我只是举例子。参考链接上是建议导出到一个文本,然后执行文本。而我是直接copy到记事本处理掉 ‘|’,粘贴到命令行执行了。都可以。

kill掉以后再执行SELECT * FROM information_schema.INNODB_TRX; 就是空了。

这时候系统就正常了

五、故障排查

  1. mysql都是autocommit配置mysql> select @@autocommit;
    ±-------------+
    | @@autocommit |
    ±-------------+
    | 0 |
    ±-------------+
    1 row in set (0.00 sec)

##如果是0 ,则改为1

mysql> set global autocommit=1;

  1. mysql的引擎检查,可以检查一下数据库引擎是不是InnoDB(mysql5.5.5以前默认是MyISAM,mysql5.5.5以后默认是InnoDB)
    show ENGINES;

查看表使用的存储引擎:show table status from dbName where name='tableName';

修改表的存储引擎:alter table tableName engine=innodb;

查看用户锁表和对表解锁的 sql 语句

<think>嗯,我现在遇到了MySQL的错误1205:“Lock wait timeout exceeded; try restarting transaction”。这个问题看起来和锁等待超时有关,但具体是怎么回事呢?我需要先理解这个错误的含义。 首先,根据错误提示,应该是在执行一个事务时,这个事务在等待某个锁的时候超时了。MySQL有一个参数叫做innodb_lock_wait_timeout,默认是50秒。也就是说,如果事务在50秒内没有获取到需要的锁,就会抛出这个错误。那为什么会发生锁等待呢? 可能的情况是,有一个长时间运行的事务占用了某些资源的锁,而其他事务在尝试访问这些资源时被阻塞。例如,事务A更新了某行数据但还没有提交,事务B也要更新同一行,这时候事务B就会等待事务A释放锁。如果事务A一直不提交,事务B就会等待直到超时。 接下来,我需要考虑如何定位问题。首先,应该检查当前数据库中的锁情况。可以通过查询information_schema库中的INNODB_TRX、INNODB_LOCKS和INNODB_LOCK_WAITS这三个表来获取相关信息。例如: ```sql SELECT * FROM information_schema.INNODB_TRX; ``` 这条语句可以看到当前运行的事务,包括事务的开始时间、状态(是否在等待锁)等信息。如果发现有长时间运行的事务,可能需要进一步分析这些事务是否正常,或者是否有必要终止它们。 另外,还可以使用SHOW ENGINE INNODB STATUS命令来查看InnoDB引擎的状态,里面会有关于锁等待的详细信息。不过这个输出的内容可能比较难懂,需要一定的经验来解析。 接下来,处理这个问题的方法可能有几种。首先,可以考虑优化事务,减少事务的执行时间,或者将大事务拆分成小事务,这样可以减少锁持有的时间。其次,如果确定某个事务已经挂起或者不需要了,可以手动终止该事务,释放锁。例如,通过查询INNODB_TRX找到对应的事务ID,然后执行KILL命令终止该事务。 另外,调整innodb_lock_wait_timeout参数也是一个办法,但需要注意这只是一个临时解决方案,增加超时时间可能只是延缓了问题,而没有根本解决锁竞争的情况。所以最好还是找到导致锁等待的根本原因,比如是否有慢查询、是否事务设计不合理等。 还有一个可能的因素是数据库的隔离级别。不同的隔离级别对锁的需求不同,比如在可重复读(REPEATABLE READ)级别下,可能会有更多的锁竞争。可以考虑调整隔离级别为读已提交(READ COMMITTED),但这可能会影响业务逻辑,需要谨慎评估。 此外,检查应用程序的逻辑是否正确处理了事务的提交和回滚。有时候,应用程序可能因为异常没有正确释放事务,导致锁一直被占用。确保所有事务在完成之后都正确提交或回滚,特别是在使用连接池的情况下,连接可能会被复用,如果前一个事务没有正确结束,可能会影响后续操作。 最后,如果问题频繁发生,可能需要更深入的性能调优,比如优化索引、分析慢查询日志、增加硬件资源等,以减少锁竞争的可能性。 总之,解决这个错误需要从多个方面入手:诊断当前的锁情况,终止阻塞的事务,优化事务设计,调整数据库参数,以及检查应用程序的逻辑。可能需要结合多种方法才能有效解决问题。</think>MySQL错误`1205 - Lock wait timeout exceeded; try restarting transaction`表示事务在等待锁时超时,通常由长时间未提交的事务或锁竞争引发。以下是逐步分析和解决方案: --- ### **1. 错误原因** - **锁等待超时**:某个事务尝试获取锁(如行锁、表锁),但因其他事务长时间占用该锁而无法获取。 - **默认超时时间**:由参数`innodb_lock_wait_timeout`控制(默认50秒),超时后自动回滚当前事务。 --- ### **2. 定位问题** #### **2.1 查看当前事务与锁** 执行以下SQL查询,检查是否有长时间未提交的事务或锁竞争: ```sql -- 查看正在运行的事务 SELECT * FROM information_schema.INNODB_TRX; -- 查看锁信息 SELECT * FROM information_schema.INNODB_LOCKS; -- 查看锁等待关系 SELECT * FROM information_schema.INNODB_LOCK_WAITS; ``` #### **2.2 分析事务状态** - 关注`INNODB_TRX`表中的字段: - `trx_started`:事务开始时间。 - `trx_query`:事务正在执行的SQL。 - `trx_state`:若为`LOCK WAIT`,表示事务在等待锁。 #### **2.3 查看InnoDB状态** ```sql SHOW ENGINE INNODB STATUS; ``` 在输出中搜索`LATEST DETECTED DEADLOCK`或`TRANSACTIONS`部分,分析锁冲突详情。 --- ### **3. 解决方案** #### **3.1 终止阻塞事务** 找到阻塞其他事务的长时间运行的事务ID(通过`INNODB_TRX`表),并终止它: ```sql KILL <transaction_id>; ``` #### **3.2 优化事务设计** - **减少事务粒度**:避免在事务中执行耗时操作(如批量更新),尽量拆分小事务。 - **及时提交或回滚**:确保事务执行后立即提交,避免未提交事务占用锁。 - **降低隔离级别**:将隔离级别从`REPEATABLE READ`改为`READ COMMITTED`(需评估业务影响): ```sql SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` #### **3.3 调整超时参数(临时方案)** ```sql -- 设置会话级超时时间(单位:秒) SET SESSION innodb_lock_wait_timeout = 100; ``` > **注意**:修改全局参数需谨慎,建议仅临时调整。 #### **3.4 检查索引与SQL性能** - **添加索引**:若未命中索引,行锁可能升级为表锁,加剧锁竞争。 - **优化慢查询**:使用`EXPLAIN`分析SQL执行计划,减少全表扫描。 --- ### **4. 预防措施** 1. **监控长事务**:定期检查`INNODB_TRX`表,或通过工具(如Prometheus+Percona插件)监控。 2. **设置事务超时**:在代码中配置事务超时时间(如Spring的`@Transactional(timeout=30)`)。 3. **避免跨服务事务**:分布式事务(如Seata)易引发锁竞争,尽量改用最终一致性方案。 --- ### **5. 总结** | 步骤 | 操作 | 目标 | |------|------|------| | 1 | 查询`INNODB_TRX` | 定位长时间未提交的事务 | | 2 | 终止阻塞事务 | 释放被占用的锁 | | 3 | 优化事务与索引 | 减少锁竞争概率 | | 4 | 调整超时参数(可选) | 临时缓解问题 | 通过以上步骤,可有效解决锁超时问题并预防其再次发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值