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也会停止工作.我该怎么办呢?
以下是我的一些经验的提示...
如果您正在进行测试驱动开发,请隔离哪些测试组合会产生错误。利用您的生态系统提供的任何机制来有选择地运行测试(例如:@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)
那是我的两分钱。希望对互联网上的人有用。
我看到重复的问题
您应该考虑通过设置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)