您可以向select语句添加FOR UPDATE以锁定它遇到的所有行.
但这还不够 – 你基本上需要锁定整个表(因为你要更新整个表),而且交易不会为你做. innoDB具有行级锁定,只有所需的行被锁定,这将在这里严重失败,因为您只选择一行,但更新所有内容.
选择整个表FOR UPDATE以锁定所有行可能会锁定所有行,但它最好是您运行的第一个SELECT.否则,您读取一行,并冻结您的视图(一致读取),然后另一个事务执行相同的操作.现在你们两个都有相同的视图 – 但是第二个事务实际上需要读取即将发生变化的数据! (第二个事务不会阻塞 – 您正在读取和锁定不同的行.系统不知道您计划更新整个表.)因此,如果您以这种方式锁定(FOR UPDATE),该语句必须是一个“冻结”你对桌子的看法.
经过一些研究,我认为唯一可行的解决方案是咨询锁定.
(MySQL中的常规LOCK命令不适用于事务.)
使用GET_LOCK函数 – 并在打开事务之前运行它,而不是之后.
即
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT GET_LOCK('folders_nested_set', ); /* remember to check to make sure the lock worked */
START TRANSACTION WITH CONSISTENT SNAPSHOT;
do work on folders table here
COMMIT;
DO RELEASE_LOCK('folders_nested_set');
确保所有使用嵌套集的函数都包含在事务中.不是为了写,而是为了确保跨SQL语句的一致读取.
即
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
do reads here
COMMIT;
除非您知道只是在一个SQL语句中读取所需的所有数据,否则您不需要这样做.
(您可以在连接到数据库之后立即执行SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ,而不是每次事务.请确保在这种情况下包含SESSION关键字.)
如果我错了,或者在这里遗漏了一些东西 – 或者即使有更好的方法,我也会非常感激,因为我正在处理同样的情况.