MySQL中的行级锁定

Irf*_*mad 6 mysql innodb rowlocking

我在一个表中有5行(1到5)。我要锁定第2行以进行一些更新,与此同时,如果有人尝试更新第4行,那么他应该可以更新。

我正在下面的代码中尝试此操作,但是我觉得它将锁定放在表级别而不是行级别。

------第一场

START TRANSACTION;
SELECT * FROM test WHERE t=1 FOR UPDATE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

-----会话2(已被阻止)

START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

gab*_*sch 5

代替FOR UPDATE使用LOCK IN SHARE MODE。FOR UPDATE防止其他事务也读取该行。LOCK IN SHARE MODE允许读取,但禁止更新。

参考:MySQL手册

------第一场

START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

-----会话2(不再被阻止了:))

START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

更新:

认识到表中没有索引上t,我有以下的解释:

首先,事务T1将行1锁定在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: use LOCK IN SHARE MODE,仅用于放置读锁。不幸的是,此选项会导致死锁。有趣的是,T2事务执行(更新第4行),而T1失败(更新第2行)。似乎T1 也锁定了行4,并且由于T2对其进行了修改,所以T1由于事务隔离级别(默认为REPEATABLE READ)而失败。最终的解决方案是使用或事务级别来处理“事务隔离级别”。READ UNCOMMITTEDREAD COMMITTED

最简单的是选项1,恕我直言,但这取决于您的选择。