mysql – 在以下情况下是否需要表锁来维护数据完整性
作者:互联网
在MySQL中,我有一个由嵌套集代表的树.操纵嵌套集需要修改表中的多行.例如,向树添加节点将需要重新排序右侧和左侧值…
SELECT @myLeft := lft FROM folders WHERE ID = ?;
UPDATE folders SET rgt = rgt + 2 WHERE rgt > @myLeft;
UPDATE folders SET lft = lft + 2 WHERE lft > @myLeft;
目前我正在将其包装在一个交易中.但是,我想知道……交易是否足以确保数据完整性?
我担心因为有两个单独的UPDATE语句,在高容量环境中这可能会导致问题……我是否还要锁定表,以确保这两个UPDATE语句之间没有任何变化?
在此先感谢您的帮助
解决方法:
您可以向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', <timeout>); /* 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关键字.)
如果我错了,或者在这里遗漏了一些东西 – 或者即使有更好的方法,我也会非常感激,因为我正在处理同样的情况.
标签:mysql,sql,locking,nested-sets 来源: https://codeday.me/bug/20190626/1296710.html