如何回滚 MySQL 事务中的所有语句?

Arm*_*oot 4 mysql database transactions rollback

我需要更新bigtable包含另一个表(FK 约束到oldsmalltable)的id 的表 ( )的特定列,以指向另一个表上的 ID(FK 约束到newsmalltable)。基本上这就是我在做什么:

DELIMITER //

CREATE PROCEDURE updatebigtable ()
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING ROLLBACK;

    START TRANSACTION;
        ALTER TABLE bigtable DROP FOREIGN KEY bigtable_ibfk_1,
            MODIFY smalltable_id SMALLINT ;
        UPDATE bigtable SET smalltable_id=CASE smalltable_id
                WHEN 1 THEN 1592
                WHEN 2 THEN 1593
                WHEN 3 THEN 1602
                ...
                ELSE 0
            END;
        ALTER TABLE bigtable ADD CONSTRAINT bigtable_ibfk_1
            FOREIGN KEY(smalltable_id) REFERENCES newsmalltable(id);
    COMMIT;
END//
DELIMITER ;

CALL updatebigtable();
DROP PROCEDURE updatebigtable;
Run Code Online (Sandbox Code Playgroud)

我需要确保如果由于某种原因新的外键约束失败(例如,对于具有不同类型的列,错误会出现在最后一个alter table语句中), theUPDATE和 first 也ALTER TABLE应该回滚,即它们应该保持原样最初是。

MySQL文档,通过使用START TRANSACTION自动提交模式,对于交易,这将禁止允许:

一旦您执行更新(修改)表的语句,MySQL 就会将更新存储在磁盘上以使其永久化。

我只发现这个问题与我的关系最小:

如何在 MySQL 存储过程中使用事务?

如果我提到的那个错误发生在事务内部,则前面的语句已经执行并且更新“永久在磁盘上完成”......

我也尝试SET autocommit=0;在创建程序之前放置,但行为仍然相同......我错过了什么吗?或者这是 MySQL 事务回滚的预期行为?

如果有什么不同,我使用的是 MySQL v.5.6.17。

Arm*_*oot 6

ALTER TABLE语句总是会导致隐式提交(来自 MySQL 文档的第 13.3.3 节,感谢wchiquito),这意味着即使它们在START TRANSACTION;...COMMIT;块内,也会有与该块内完成的更改数量一样多的提交。

锁定表也不是一种选择,因为(来自 问题ALTER TABLE):

如果您ALTER TABLE在事务表上使用或者如果您使用的是 Windows,ALTER TABLE如果您LOCK TABLE对它进行了操作,则解锁该表。这样做是因为 InnoDB 和这些操作系统不能删除正在使用的表。

在执行 alter 和 update 语句时避免不必要的读/写的唯一选择是模拟以下所有步骤ALTER TABLE

  1. 使用请求的结构更改创建一个名为 A-xxx 的新表。
  2. 将原始表中的所有行复制到 A-xxx。
  3. 将原始表重命名为 B-xxx。
  4. 将 A-xxx 重命名为您的原始表名。
  5. 删除 B-xxx。

这样可以在新表中进行更新(在第 2 步之后),唯一bigtable不可用的时间是在执行第 3 步和第 4 步(重命名)时。