`UPDATE tbl SET col = col + 1` 需要 LOCK TABLE 吗?
is a LOCK TABLE needed for `UPDATE tbl SET col = col + 1`?
假设 col
为 0,并且 100 个客户端同时试图将其增加 1,这里需要 LOCK TABLE 吗?
LOCK TABLE tbl;
UPDATE tbl SET col = col + 1;
UNLOCK TABLE;
或者我可以做吗
UPDATE tbl SET col = col + 1;
并确保 col 变为 100? (例如,mariadb 确保 none 其中两次读取相同的值~)
我基本上是在尝试做相当于这个 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 在家~)
首先:您的查询似乎缺少 WHERE
子句,该子句指定应更新哪一行。据推测,您会为此使用主键列,比如 id
- 例如:
UPDATE tbl SET col = col + 1 WHERE id = 1;
现在,假设您同时有许多并发进程 运行 此查询,那么我不建议手动锁定该行。相反,让数据库为您管理并发。它实际上会在幕后为您锁定行,并按顺序执行并发查询,在提交前一个事务时将行交给下一个事务。如果初始值为 0
并且有 100
个并发进程,则最终值为 100
。
首先,不要使用MyISAM,使用InnoDB。不要将 LOCK TABLES
与 InnoDB 一起使用。
在任何情况下,您都不需要为单个查询使用任何类型的锁。查询具有隐式锁。 (MyISAM 锁定 table;InnoDB 锁定行。)
当您有 多个 语句需要“原子”地保持在一起时,需要锁/事务。请注意您的示例如何同时进行读取和写入,以及如何使用读取的值进行操作。
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()
。但这些是规则的有限例外,如果您希望多个线程处理相同的数据,您应该真正考虑多语句事务。
假设 col
为 0,并且 100 个客户端同时试图将其增加 1,这里需要 LOCK TABLE 吗?
LOCK TABLE tbl;
UPDATE tbl SET col = col + 1;
UNLOCK TABLE;
或者我可以做吗
UPDATE tbl SET col = col + 1;
并确保 col 变为 100? (例如,mariadb 确保 none 其中两次读取相同的值~)
我基本上是在尝试做相当于这个 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 在家~)
首先:您的查询似乎缺少 WHERE
子句,该子句指定应更新哪一行。据推测,您会为此使用主键列,比如 id
- 例如:
UPDATE tbl SET col = col + 1 WHERE id = 1;
现在,假设您同时有许多并发进程 运行 此查询,那么我不建议手动锁定该行。相反,让数据库为您管理并发。它实际上会在幕后为您锁定行,并按顺序执行并发查询,在提交前一个事务时将行交给下一个事务。如果初始值为 0
并且有 100
个并发进程,则最终值为 100
。
首先,不要使用MyISAM,使用InnoDB。不要将 LOCK TABLES
与 InnoDB 一起使用。
在任何情况下,您都不需要为单个查询使用任何类型的锁。查询具有隐式锁。 (MyISAM 锁定 table;InnoDB 锁定行。)
当您有 多个 语句需要“原子”地保持在一起时,需要锁/事务。请注意您的示例如何同时进行读取和写入,以及如何使用读取的值进行操作。
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()
。但这些是规则的有限例外,如果您希望多个线程处理相同的数据,您应该真正考虑多语句事务。