【问题标题】:MySQL Transaction in Stored Procedure does not ROLLBACK存储过程中的 MySQL 事务不回滚
【发布时间】:2020-07-08 17:12:52
【问题描述】:

这是我的存储过程:

CREATE PROCEDURE `procedureName`
(
    IN var1 VARCHAR(45),
    IN var2 VARCHAR(100),
    IN var3 VARCHAR(45),
    IN var4 DATE,
    IN someMoreVars VARCHAR(100)
)
COMMENT 'just a comment'
BEGIN
    DECLARE tempVar INT DEFAULT -1;

    DECLARE exit handler for sqlexception
      BEGIN
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'SQLError occured. Triggered ROLLBACK';
        -- ERROR
      ROLLBACK;
    END;

    DECLARE exit handler for sqlwarning
      BEGIN
      SIGNAL SQLSTATE '35000' SET MESSAGE_TEXT = 'SQLWarning occured. Triggered ROLLBACK';
        -- WARNING
      ROLLBACK;
    END;

    START TRANSACTION;
        INSERT INTO `schemaName`.`table1` (`column1`, `column2`, `moreColumns`)
            VALUES (var1, var2, moreVars);
        SELECT LAST_INSERT_ID() INTO tempVar;
        INSERT INTO `schemaName`.`table2` (`column1`, `column2`, `evenMoreColumns`)
            VALUES (tempVar, var3, var4);
    COMMIT;

END

为什么该存储过程不回滚?当我使用适用于第一次插入但在第二次插入时引发异常的参数时,此过程不会回滚,我最终会在第一个表中得到数据,但在第二个表中没有数据。

我正在使用 InnoDB 引擎。

我已经使用 MySQL Workbench 测试了这种行为,因为它在 GUI 中内置了这种奇怪的自动提交行为,我还通过从 C# 脚本调用过程来测试它。

我还检查了 LAST_INSERT_ID() 函数是否在文档中被提及为导致隐式提交的函数。但在列表中没有找到它。或者该函数是否调用了另一个确实导致隐式提交的函数?如果是,是否有任何解决方法? 我需要调用这个函数来使用它的 PRIMARY KEY 作为第二个表中的 FOREIGN KEY。 如果此信息有帮助:我也在使用触发器。

这是其中一张表的插入触发器(它们几乎在插入/更新/删除的所有表中):

CREATE DEFINER = CURRENT_USER TRIGGER `schema`.`table1_AFTER_INSERT` AFTER INSERT ON `table1` FOR EACH ROW
BEGIN
    INSERT INTO `schema`.`table1_audit` (`table1_audit_action`, `table1_audit_timestamp`, `table1_audit_user`, `table1_val1`, `table1_some_more_columns`)
    VALUES ('insert', CURRENT_TIMESTAMP(), SESSION_USER(), NEW.table1_val1, NEW.table1_some_more_columns);
END

谢谢:)

【问题讨论】:

  • 看看我对 sqlexecepotions stackoverflow.com/a/60351232/5193536987654321@的回答
  • 谢谢,这绝对很有趣。所以你认为这可能是当前 MySQL Server 版本中的一个 Bug 吗?但是我在第二次插入中导致异常的原因是,在配置为 NOT NULL 的列中将其中一个值设置为 null。我想说这并不是一个特殊的例外,但可能是最常见的例外之一。你真的认为连这个异常都没有得到正确处理吗?
  • 触发器中的代码可能会导致提交,因为第一个 INSERT 上的触发器将在第二个 INSERT 之前运行
  • 因为并非所有错误都会触发 sqlexecption,这取决于错误发生的位置。所以得到正确的数字,然后像我在第二个代码块中那样编程
  • @Nick Ohh 这对我来说很有意义。有什么办法可以防止这种情况发生吗?我将尝试在我的过程中明确设置自动提交。但我想这无济于事,因为它不应该对交易产生影响。还有其他建议吗?

标签: c# mysql database


【解决方案1】:

只是为了让这篇文章与最新信息保持同步: 几天/几周前,我自己找到了解决此错误的解决方案。

事实证明,问题在于必须在“SIGNAL”之前调用“ROLLBACK”。如果有人有详细解释为什么会这样,请随时添加该信息。但是在发出异常信号后根本不可能回滚。 所以下面的代码应该可以工作:

DECLARE exit handler for sqlexception
BEGIN
    -- ERROR
  ROLLBACK;
  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'SQLError occured. Triggered ROLLBACK';
END;

当然,SQLWarning 也是如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    • 2012-04-15
    相关资源
    最近更新 更多