如何使用Laravel锁定表格?

9
我想在事务中锁定一个表。类似于这样的操作:
  DB::transaction(function (){
    DB::statement('LOCK TABLES important_table WRITE');
    //....
  });

然而,代码行DB::statement('LOCK TABLES important_table WRITE');总是会触发以下错误:

SQLSTATE[HY000]: General error: 2014 无法执行查询,因为其他未缓冲的查询仍在执行中。请考虑使用PDOStatement::fetchAll()。或者,如果您的代码只会运行在mysql上,您可以通过设置PDO::MYSQL_ATTR_USE_BUFFERED_QUERY属性启用查询缓冲。(SQL: LOCK TABLES officeSeal WRITE)

如何在Laravel中锁定表格?


1
我想知道为什么你需要锁定InnoDB表。你真的希望InnoDB像MyISAM一样行事吗?此外,使用TRANSACTION将锁定所需的记录。 - Raymond Nijland
@RaymondNijland 我需要锁定整个表的原因可以在 https://dba.stackexchange.com/questions/223608/using-transactions-without-select-for-update/223609(请参见答案+评论)找到。 - Adam
除了 MySQL 中的 TRANSACTIONS,也支持事务隔离。这方面的资料值得学习,详情请见:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html。 - Raymond Nijland
@RaymondNijland,不确定我是否正确理解了您的意思 - 您是建议将计算出的间隙复制到临时表中吗?因为我在步骤1中计算间隙,而不是在步骤3中。抱歉我有点困惑。我已经阅读了有关事务隔离的部分。 - Adam
不要在InnoDB中使用LOCK TABLES - Rick James
4个回答

13

在Laravel中,可以像这样锁定表:

DB::statement(DB::raw('LOCK TABLES important_table WRITE'));

然而,您应该知道,锁定表的性能并不是很好,如果可能的话应该使用行级锁。


3
如果有人尝试了这个答案但失败了,请尝试这个:DB::unprepared('LOCK TABLES important_table WRITE'); - 尤川豪
https://dev59.com/EF8e5IYBdhLWcg3w0NCO - 尤川豪
1
@尤川豪 你使用的是哪个版本的Laravel?自2013年以来,似乎应该已经修复了 https://github.com/laravel/framework/issues/53 - Adam
2
我只想提醒其他人,DB::raw 只会生成字符串。它不会直接执行 SQL 语句。 - 尤川豪
那么什么是行锁定?如何实现它? - shintaroid

4
正如其他用户在评论中指出的那样,我不确定表锁绝对是唯一的出路。但是,如果您坚持使用,您可以使用Laravel的Pessimistic Locking。即文档中提到的sharedLock()lockForUpdate()方法。
您会注意到文档中的示例没有使用Eloquent,而是依赖于Query Builder。但是,this Q&A似乎表明它也可以使用Eloquent完成。
阅读this article可能也很值得,该文章对Laravel中的悲观锁和乐观锁实现进行了对比。

1

DB::unprepared('LOCK TABLES important_table WRITE'); 这个对我有用


0
DB::statement(DB::raw('LOCK TABLES the_table WRITE'));

请勿重复现有答案,特别是如果您的答案没有任何解释。 - Nico Haase
@NicoHaase 这不是重复的,将DB :: raw放入DB :: statement中使得这个答案独一无二。 - Sajjad
请随意在您的答案中添加一些解释,以便其他人可以从中学习 - Nico Haase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接