获取"超过锁定等待超时;尝试重新启动事务"即使我没有使用事务

Jas*_*ett 237 mysql sql timeout lock-timeout

我正在运行以下MySQL UPDATE语句:

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Run Code Online (Sandbox Code Playgroud)

我没有使用交易,为什么我会收到此错误?我甚至尝试重新启动我的MySQL服务器,它没有帮助.

该表有406,733行.

Eri*_*ski 298

如何强制解锁MySQL中的锁定表:

像这样打破锁可能导致数据库中的原子性不会在导致锁定的sql语句上强制执行.

这是hackish,正确的解决方案是修复导致锁定的应用程序.然而,当美元上线时,快速反击将使事情再次发生变化.

1)输入MySQL

mysql -u your_user -p
Run Code Online (Sandbox Code Playgroud)

2)让我们看一下锁定表的列表

mysql> show open tables where in_use>0;
Run Code Online (Sandbox Code Playgroud)

3)让我们看一下当前进程的列表,其中一个是锁定你的表

mysql> show processlist;
Run Code Online (Sandbox Code Playgroud)

4)杀死其中一个过程

mysql> kill <put_process_id_here>;
Run Code Online (Sandbox Code Playgroud)

  • 废话,这可以让你撤消一个混乱,然后修复应用程序.如果我可以为这个问题给这个家伙100票,我现在必须解决这个问题. (57认同)
  • 这是危险和骇人听闻的.正确的解决方案是修复您的应用程序. (13认同)
  • 我同意Lizardx.在我没有权限调用SHOW ENGINE INNODB STATUS的情况下,这是一个非常有用的解决方案 (7认同)
  • 如何以这种方式查杀长时间运行的查询_dangerous_?客户端调用只会出错. (7认同)
  • @EricLeschinski我明白你的观点,但我不得不问为什么你会在_Life-Critical_系统上使用像_MySQL_这样的草率数据库呢? (5认同)
  • 大家只是不要忘记索引相关列,很多时候这就是导致锁定的原因 (3认同)
  • 此方法可帮助我在没有PROCESS权限的情况下中断锁定. (2认同)

Mar*_*rkR 192

您正在使用交易; autocommit不会禁用事务,它只是使它们在语句结束时自动提交.

发生的事情是,其他一些线程在一些记录上持有记录锁(你正在更新表中的每条记录!)太久了,你的线程正在超时.

您可以通过发出一个来查看事件的更多细节

SHOW ENGINE INNODB STATUS
Run Code Online (Sandbox Code Playgroud)

事件发生后(在sql编辑中).理想情况下,在安静的测试机上进行此操作.

  • 从命令行:mysql [插入凭据] -e"SHOW ENGINE INNODB STATUS\G"> innodb_stat.txt (13认同)
  • 在单个事务期间在同一行上运行多个 (2+) UPDATE 查询也会导致此错误。 (8认同)
  • 有没有办法将输出保存到文件?我试过 SHOW ENGINE INNODB STATUS\G &gt; innodb_stat.txt 但没有用。 (2认同)

小智 90

mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+
Run Code Online (Sandbox Code Playgroud)

现在再次触发锁定.您有100秒的时间向SHOW ENGINE INNODB STATUS\G数据库发出一个并查看哪个其他事务正在锁定您的数据库.

  • 这个答案并没有解释为什么提问者得到他们的错误.你能详细说明为什么除了给出答案之外? (8认同)
  • 这是什么答案? (5认同)
  • 虽然这不能直接回答这个问题,但对我来说这是解决这个问题的一个很好的参考. (4认同)
  • @ArtB https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout 本质上,OP收到错误,因为在表上调用了锁,并且在结束之前经过了时间事务超出了“lock_wait_timeout”值 (2认同)

小智 64

看看您的数据库是否经过微调.特别是交易隔离.增加innodb_lock_wait_timeout变量不是一个好主意.

检查mysql cli中的数据库事务隔离级别:

mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

您可以获得改进de隔离级别的改进,使用像READ COMMITTED这样的oracle而不是REPEATABLE READ(InnoDB Defaults)

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 
Run Code Online (Sandbox Code Playgroud)

另外,如果必要,请尝试使用SELECT FOR UPDATE.

  • 请注意:MySQL 8 已将“tx_isolation”变量重命名为“transaction_isolation”。 (6认同)
  • 不过,必须小心了解当您从读隔离更改为 READ COMMITTED 时会遇到什么情况。您最终可能会得到您可能想要避免的脏数据。[维基百科隔离](https://en.wikipedia.org/wiki/Isolation_(database_systems)) (3认同)
  • 对我来说很有用,my.cnf版本是[mysqld] transaction-isolation = READ-COMMITTED (2认同)

Bas*_*MHL 16

没有一个建议的解决方案适合我,但确实如此.

有些东西阻止了查询的执行.很可能是另一个查询更新,插入或删除查询中的一个表.你必须找出它是什么:

SHOW PROCESSLIST;
Run Code Online (Sandbox Code Playgroud)

找到阻止进程后,找到它id并运行:

KILL {id};
Run Code Online (Sandbox Code Playgroud)

重新运行初始查询.


Jam*_*s C 12

MarkR所说的100%.autocommit使每个语句成为一个语句事务.

SHOW ENGINE INNODB STATUS应该给你一些关于死锁原因的线索.仔细查看慢速查询日志,看看还有什么查询表并尝试删除正在执行完整表扫描的任何内容.行级锁定工作正常但不是在您尝试锁定所有行时!


Ahm*_*rif 6

mysql->SHOW PROCESSLIST;
kill xxxx; 
Run Code Online (Sandbox Code Playgroud)

然后杀死睡眠中的哪个。就我而言,它是 2456。

在此处输入图片说明


小智 6

尝试更新以下两个参数,因为它们必须具有默认值。

innodb_lock_wait_timeout = 50

innodb_rollback_on_timeout = ON

要检查参数值,您可以使用以下 SQL。

显示全局变量,例如“innodb_rollback_on_timeout”;


Joh*_*ane 5

你能更新这个表中的任何其他记录,还是这个表被大量使用?我在想的是,当它试图获取一个需要更新此记录的锁时,设置的超时已经超时.您可以增加可能有用的时间.

  • 也许在`my.cnf`中`innodb_lock_wait_timeout` (3认同)

小智 5

在我们的例子中,问题与锁本身没有太大关系。

问题是我们的应用程序端点之一需要并行打开 2 个连接来处理单个请求。

例子:

  1. 打开第一个连接
  2. 开始交易1
  3. 锁定 table1 中的 1 行
  4. 打开第二个连接
  5. 开始交易2
  6. 锁定 table2 中的 1 行
  7. 提交交易2
  8. 释放第二个连接
  9. 提交交易1
  10. 释放第一个连接

我们的应用程序的连接池限制为 10 个连接。

不幸的是,在负载下,一旦使用了所有连接,应用程序就停止工作,我们开始遇到这个问题。我们有几个请求需要打开第二个连接才能完成,但由于连接池限制而无法完成。因此,这些请求长时间锁定 table1 行,导致后续需要锁定同一行的请求引发此错误。

解决方案:

  • 短期内,我们通过增加连接池限制来修复该问题。
  • 从长远来看,我们删除了所有嵌套连接,以彻底解决该问题。

尖端:

您可以通过尝试将连接池限制降低到 1 并测试您的应用程序来轻松检查是否有嵌套连接。