我在表格中有5行(1到5)。我希望第2行锁定某些更新,同时如果有人试图更新第4行,那么他应该能够更新。
我正在尝试使用下面的代码,但我觉得它将锁定放在表级别而不是行级别。
------第1节
START TRANSACTION;
SELECT * FROM test WHERE t=1 FOR UPDATE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
-----会话2(被阻止)
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
答案 0 :(得分:4)
而不是FOR UPDATE
使用LOCK IN SHARE MODE
。 FOR UPDATE
也阻止其他事务读取行。 LOCK IN SHARE MODE
允许读取,但阻止更新。
参考:MySQL Manual
------第1节
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;
<强>更新强>
在t
上意识到表没有索引,我有以下解释:
首先,事务T1锁定SELECT * FROM test WHERE t=1 FOR UPDATE
接下来,事务T2尝试执行UPDATE test SET NAME='irfandd' WHERE t=4
。要找出受影响的行,需要扫描所有行,包括第1行。但是这是锁定的,所以T2必须等到T1结束。
如果存在任何类型的索引,WHERE t=4
可以使用索引来确定第1行是否包含t=4
,因此无需等待。
选项1:在test.t
上添加索引,以便您的更新可以使用它。
选项2:使用LOCK IN SHARE MODE
,用于仅设置读锁定。
不幸的是,这个选项会造成死锁。有趣的是,T2事务执行(更新第4行),T1失败(更新第2行)。似乎T1读取锁定第4行,并且由于T2修改它,因为事务隔离级别(REPEATABLE READ by default),T1失败。使用READ UNCOMMITTED
或READ COMMITTED
交易级别,最终解决方案将使用Transaction Isolation Levels。
最简单的是选项1 ,恕我直言,但这取决于您的可能性。
答案 1 :(得分:0)
我发现下面的选项更合适我同时从并发会话生成40000个数字。我没找到任何重复的号码。没有下面的命令我生成10000个数字,发现5个重复的数字。
START TRANSACTION
SELECT * FROM test WHERE t = 1 FOR UPDATE;
更新测试SET NAME ='irfandd'WHERT = 2;
COMMIT;