【问题标题】:How to rollback all statements inside a MySQL Transaction?如何回滚 MySQL 事务中的所有语句?
【发布时间】:2016-03-05 09:31:19
【问题描述】:

我需要更新包含另一个表的 id 的表 (bigtable) 的特定列(FK 约束到 oldsmalltable)以指向另一个表上的 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;

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

根据MySQL documentation,通过使用START TRANSACTION,该事务的自动提交模式被禁用,这将不允许

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

我只发现这个问题与我的关系微乎其微:

How can I use transactions in my MySQL stored procedure?

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

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

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

【问题讨论】:

标签: mysql database transactions rollback


【解决方案1】:

ALTER TABLE 语句总是会导致隐式提交(section 13.3.3 from MySQL docs,感谢wchiquito),这意味着即使它们在START TRANSACTION; ... COMMIT; 块内,也会有尽可能多的提交作为在该块内完成的更改次数。

锁定表格也不是一种选择,因为 (from problems with 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 步(重命名)时。

【讨论】:

    【解决方案2】:

    使用 TRY CATCH 块 BEGIN TRAN before BEGIN TRY 和 ROLLBACK TRAN 在 CATCH 块内

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 2012-11-12
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多