所以 select for update 的语法是这样的
SELECT * //1st query
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test //2nd query
SET parent = 100
WHERE id = 4;
我猜锁定部分是第一行。
因此,当执行第一组查询时,我不应该能够选择和修改该行id = 4
(顺便说一句,这是主键)。但是,我仍然可以选择行id = 4
在我更新任何内容之前,这意味着另一个线程可能会进入并尝试在第二行命中之前选择并更新同一行,从而导致并发问题。
但是当我锁定整个表时,如下所示
LOCK TABLES test WRITE;
其他事务处于挂起状态,等待锁被释放。我想使用的唯一原因SELECT FOR UPDATE
而不是表锁是因为这里引用的原因https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html
如果我在这里引用它们,如下所示
LOCK TABLES 不能很好地处理事务。即使您使用
“SET autommit=0”语法可以发现不需要的副作用。为了
例如,在事务中发出第二个 LOCK TABLES 查询将
提交您的待处理更改:
SET autocommit=0;
LOCK TABLES foo WRITE;
INSERT INTO foo (foo_name) VALUES ('John');
LOCK TABLES bar WRITE; -- Implicit commit
ROLLBACK; -- No effect: data already committed
在许多情况下,LOCK TABLES 可以替换为 SELECT ... FOR UPDATE
它是完全事务感知的并且不需要任何特殊语法:
START TRANSACTION;
SELECT COUNT(*) FROM foo FOR UPDATE; -- Lock issued
INSERT INTO foo (foo_name) VALUES ('John');
SELECT COUNT(*) FROM bar FOR UPDATE; -- Lock issued, no side effects
ROLLBACK; -- Rollback works as expected
因此,如果我可以在实际更新发生之前访问选择更新的行,那么到底是什么SELECT FOR UPDATE
锁定?另外,如何测试应用程序中的行是否被锁定? (它显然不适用于我编写的第一组查询)
该表是使用InnoDB引擎创建的
弗朗西斯科的解决方案
下面的两个解决方案都会导致parent 为1
UPDATE test
SET parent = 99
WHERE id = 4;
COMMIT;
START TRANSACTION;
SELECT *
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test
SET parent = 98
WHERE id = 4; //don't commit
START TRANSACTION;
SELECT *
FROM test
WHERE parent = 98 FOR UPDATE; //commit did not happens so the id=4 document would still be parent = 99
UPDATE test
SET parent = 1
WHERE id = 4;
COMMIT; //parent = 1 where id = 4
另一种只是将父条件更改为 99 而不是 98
UPDATE test
SET parent = 99
WHERE id = 4;
COMMIT;
START TRANSACTION;
SELECT *
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test
SET parent = 98
WHERE id = 4; //Don't commit
START TRANSACTION;
SELECT *
FROM test
WHERE parent = 99 FOR UPDATE; //targets parent = 99 this time but id=4 still results in parent =1
UPDATE test
SET parent = 1
WHERE id = 4;
COMMIT;
第一组查询的运行就像 id=4 文档已首先提交给 Parent = 98 一样。但是,第二组查询运行时就好像 id=4 文档尚未提交给 Parent = 99 一样。这里如何保持一致性?