Laravel - 超出锁定等待超时

Sno*_*all 11 php mysql transactions laravel

我的代码中有很多事务,如果在其中一个不触发提交或回滚的事务中执行时发生错误,则数据库被锁定,任何后续访问数据库的尝试都会导致:

production.ERROR: PDOException: SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction in /home/forge/default/vendor/laravel/framework/src/Illuminate/Database/Connection.php:390

在控制器中:

DB::beginTransaction();

try {
    //Code that uses exec() to process some images. <-- If code breaks here, then the above error appears on subsequent requests.
    //Code that accesses the database
}
catch(\Exception $e){
    DB::rollback();
    throw $e;
}
DB::commit();
Run Code Online (Sandbox Code Playgroud)

所以即使是php artisan migrate:refresh或php artisan migrate:reset也会停止工作.我该怎么办呢?

Sto*_*tie 7

以下是我的一些经验的提示...

如果您正在进行测试驱动开发,请隔离哪些测试组合会产生错误。利用您的生态系统提供的任何机制来有选择地运行测试(例如:@group only测试方法和phpunit --group only

接下来,减少锁定等待超时 ( SET GLOBAL innodb_lock_wait_timeout = 10)。通过这种方式,您可以获得快速反馈,而不必花费一整天时间等待测试运行。里程可能会有所不同。根据您的具体情况进行调整。

第三,寻找未关闭的事务,即开始时没有回滚或提交。结果证明这正是我的问题所在。我的 try/catch 没有包装足够的逻辑,并且在开始事务和 try-catch-rollback 之间出错。

第四,考虑将事务的所有部分放在同一个 try-catch 中,这有利于确保所有部分都在那里并且很容易看到。例子:

    try {
        DB::beginTransaction();
        $this->someMethodThatMightThrow();
        DB::commit();
    } catch (Exception $e) {
        DB::rollBack();
        throw $e;
    }
Run Code Online (Sandbox Code Playgroud)

那是我的两分钱。希望对互联网上的人有用。

  • 我在 phpunit 运行时遇到了这个错误,但不知道为什么。我在这里发现@Stoutie 的回答对追查原因非常有帮助,并最终找到了一个被覆盖的 `tearDown()` 方法,我没有调用 `parent::tearDown()`。基本上,如果您不调用`parent::tearDown()`,那么事务仍处于打开状态,并且从未发生过回滚/断开连接。 (9认同)

Tín*_*ang 6

我看到重复的问题

如何在MySQL上调试超出锁等待超时的时间?

您应该考虑通过设置innodb_lock_wait_timeout来增加InnoDB的锁定等待超时值,默认值为50秒

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+
1 row in set (0.01 sec)
Run Code Online (Sandbox Code Playgroud)

您可以在此行中将其永久设置为/etc/my.cnf中的较高值。

[mysqld]
innodb_lock_wait_timeout=120
Run Code Online (Sandbox Code Playgroud)

并重启mysql。如果您目前无法重启mysql,请运行以下命令:

SET GLOBAL innodb_lock_wait_timeout = 120`; 
Run Code Online (Sandbox Code Playgroud)

您也可以在整个会话期间进行设置

SET innodb_lock_wait_timeout = 120; 
Run Code Online (Sandbox Code Playgroud)