代替FOR UPDATE
use LOCK IN SHARE MODE
. FOR UPDATE
也阻止其他事务读取该行。LOCK IN SHARE MODE
允许读取,但阻止更新。
参考:MySQL手册 http://dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html
------ 第一节
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- 会话 2(不再被阻止:))
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Update:
意识到这一点该表没有索引 on t
,我有以下解释:
首先,事务T1锁定row 1 in SELECT * FROM test WHERE t=1 FOR UPDATE
接下来,事务T2尝试执行UPDATE test SET NAME='irfandd' WHERE t=4
。要找出受影响的行,需要扫描所有行,包括row 1。但它已被锁定,因此 T2 必须等待 T1 完成。
如果有任何类型的索引,WHERE t=4
可以使用索引来决定是否row 1包含t=4
或没有,所以不需要等待。
选项1:添加索引test.t
这样您的更新就可以使用它。
选项2: use LOCK IN SHARE MODE
,仅用于放置读锁。
不幸的是,这个选项会造成僵局。有趣的是,T2 事务执行(更新第 4 行),而 T1 失败(更新第 2 行)。看来T1读锁row 4另外,由于 T2 修改了它,T1 由于事务隔离级别而失败(默认可重复读取 https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html#isolevel_repeatable-read)。最终的解决方案是玩事务隔离级别 https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-model.html, using READ UNCOMMITTED
or READ COMMITTED
交易水平。
最简单的是Option 1,恕我直言,但这取决于你的可能性。