“update tbl set col=col+1”是否需要锁表?

yjghlzjz  于 2021-07-27  发布在  Java
关注(0)|答案(2)|浏览(332)

这么说吧 col 是0,并且100个客户机正试图同时将其增加1,这里是否需要锁表?

LOCK TABLE tbl;
UPDATE tbl SET col = col + 1;
UNLOCK TABLE;

或者我可以这样做吗

UPDATE tbl SET col = col + 1;

确保col变成100(例如,mariadb确保它们都不会读取相同的值两次~)
我基本上是在尝试做这个php代码的等效代码

$fp = fopen("counter.txt", "r+b");
flock($fp, LOCK_EX);
$number = (int) stream_get_contents($fp);
$number += 1;
rewind($fp);
fwrite($fp, (string) $number);
flock($fp, LOCK_UN);
fclose($fp);

但是用数据库而不是文本文件
我怀疑mariadb和mysql在这一点上有什么区别,但如果有,我想了解一下,所以将两者都标记起来(作为一个轶事,我在工作中使用mysql,在家中使用mariadb~)

fzsnzjdm

fzsnzjdm1#

首先,不要使用myisam,使用innodb。不要使用 LOCK TABLES 与innodb合作。
在任何情况下,对于单个查询都不需要任何类型的锁。查询具有隐式锁(米桑锁着table;innodb锁定行。)
当您有多个语句需要“原子”地保存在一起时,就需要锁/事务。请注意您的示例如何执行读写操作,以及如何使用read值执行某些操作。
innodb中的等效值(伪代码):

START TRANSACTION;
$num = SELECT num FROM tbl WHERE id=1  FOR UPDATE;
$num = $num + 1;
UPDATE tbl SET num = $num;
COMMIT;

是的, UPDATE table SET num = num + 1 在原子上做同样的事情,但是它不允许你用 num .
mariadb有一个 RETURNS 在某些情况下。有 LAST_INSERT_ID() . 但是,如果您希望有多个线程处理同一数据,那么您就应该真正考虑多语句事务的规则,这些是有限的例外。

yshpjwxd

yshpjwxd2#

首先:您的查询似乎缺少 WHERE 子句,指定应更新哪一行。大概,您会为此使用一个主键列,比如 id -例如:

UPDATE tbl SET col = col + 1 WHERE id = 1;

现在,假设您有许多并发进程同时运行这个查询,那么我不建议手动锁定行。相反,让数据库为您管理并发性。它实际上会在后台为您锁定该行,并按顺序执行并发查询,在提交上一个事务时将该行移交给下一个事务。如果初始值为 0 还有一些 100 并发进程,您将以 100 作为最终值。

相关问题