【发布时间】:2011-07-21 15:29:56
【问题描述】:
我很困惑你为什么要指定FOR UPDATE——为什么数据库会关心你要如何处理来自SELECT的数据?
编辑:对不起,我问的问题很糟糕。我知道文档说它把事情变成了“锁定读取”——我想知道的是“在指定FOR UPDATE 和不指定它之间存在哪些可观察行为会有所不同的情况——也就是说,什么那个锁具体需要吗?
【问题讨论】:
我很困惑你为什么要指定FOR UPDATE——为什么数据库会关心你要如何处理来自SELECT的数据?
编辑:对不起,我问的问题很糟糕。我知道文档说它把事情变成了“锁定读取”——我想知道的是“在指定FOR UPDATE 和不指定它之间存在哪些可观察行为会有所不同的情况——也就是说,什么那个锁具体需要吗?
【问题讨论】:
http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
这与在事务中锁定表有关。假设您有以下内容:
START TRANSACTION;
SELECT .. FOR UPDATE;
UPDATE .... ;
COMMIT;
在 SELECT 语句运行后,如果您有来自其他用户的另一个 SELECT,它不会运行,直到您的第一个事务到达 COMMIT 行。
还要注意事务之外的FOR UPDATE 是没有意义的。
【讨论】:
START TRANSACTION; SELECT MAX(id+1) AS newid FROM thetable FOR UPDATE; INSERT INTO thetable (id) VALUES (newid); COMMIT; 的事情——而且你知道MAX() + 1 返回的值不会与其他人冲突?
这旨在解决的特定情况是当您需要读取和更新列中的值时。有时您可以先更新列(锁定它)然后再读取它,例如:
UPDATE child_codes SET counter_field = counter_field + 1;
SELECT counter_field FROM child_codes;
这将返回 counter_field 的新值,但这在您的应用程序中可能是可以接受的。如果您试图重置该字段(因此您需要原始值),或者如果您有一个无法在更新语句中表达的复杂计算,这是不可接受的。在这种情况下,为了避免两个连接竞相更新同一列,您需要锁定该行。
如果您的 RDBMS 不支持 FOR UPDATE,那么您可以通过执行无用的更新来模拟它,例如
UPDATE child_codes SET counter_field = counter_field;
SELECT counter_field FROM child_codes;
UPDATE child_codes SET counter_field = 0;
【讨论】:
它将锁定行(或整个表),以便行不能在另一个会话中同时更新。在事务提交或回滚之前一直保持锁定。
【讨论】:
它会创建一个锁定读取,这样在你完成之前没有人可以更新它,例如
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
请看这里http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
【讨论】:
FOR UPDATE 不会影响 UPDATE 语句 - 因为它们是分开的用分号分隔的语句(因此我对为什么需要存在该指令感到困惑)。
SELECT FOR UPDATE 告诉 RDBMS 您要锁定这些行,这样在您更新并提交或回滚并解锁它们之前,其他人无法访问它们:
【讨论】: