2

简短版本: 如果有一个已启动的事务可能会回滚,那么如何将某些内容记录到日志表中?(事务的回滚也会回滚日志条目,这是这里的问题。)

长版:

我有一个存储过程,让我们调用它sp_A来调用其他存储过程,让我们调用它们sp_Bsp_C. 为了一致性起见, anXA TRANSATCION开始于sp_A. 我真正想做的是记录执行sp_Bsp_C失败,如果是,哪些是传递给失败的存储过程的参数。但是,sp_Bsp_C某些表中进行一些插入操作时,我需要做一个XA ROLLBACKifsp_Bsp_C失败。

所以我的问题是:如何在事务中登录表(或如何在事务范围之外执行插入语句)?

给你一个我想做的小例子(我已经简化了代码并重命名了大多数用于解决问题的参数/变量,我永远不会梦想使用像a,bc;-) 这样的参数名称):

存储过程sp_A如下所示:

CREATE PROCEDURE `sp_A`
(
  IN a INT,
  IN b VARCHAR(64),
  OUT c INT
)
sp_label:BEGIN
  DECLARE l_errorMessage TEXT;
  DECLARE l_spSuccess INT;
  DECLARE l_errorOccured INT DEFAULT 0;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN
    SET l_errorOccured = 1;
  END;

  XA START 'sp_A';

  CALL sp_B(a, b, l_spSuccess);

  IF l_errorOccured OR (l_spSuccessResult < 0) THEN
    XA END 'sp_A';
    XA ROLLBACK 'sp_A';
    SET c = -1;
    SET l_errorMessage = CONCAT('CALL sp_B(', a, ', ', b, ', l_spSuccess);');
    CALL sp_Log(l_errorMessage);
    LEAVE sp_label;
  END IF;

  CALL sp_C(a, b, l_spSuccess);

  IF l_errorOccured OR (l_spSuccessResult < 0) THEN
    XA END 'sp_A';
    XA ROLLBACK 'sp_A';
    SET c = -2;
    SET l_errorMessage = CONCAT('CALL sp_C(', a, ', ', b, ', l_spSuccess);');
    CALL sp_Log(l_errorMessage);
    LEAVE sp_label;
  END IF;

  XA END 'sp_A';
  XA COMMIT 'sp_A';
  SET c = 1;
END;

存储过程sp_B如下所示(sp_C看起来很相似):

CREATE PROCEDURE `sp_B`
(
  IN a INT,
  IN b VARCHAR(64),
  OUT c INT
)
sp_label:BEGIN
  DECLARE l_errorMessage TEXT;
  DECLARE l_spSuccess INT;
  DECLARE l_errorOccured INT DEFAULT 0;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN
    SET l_errorOccured = 1;
  END;

  INSERT INTO `someTable` (`a`, `b`) VALUES (a, b);

  IF l_errorOccured THEN
    SET c = -1;
    SET l_errorMessage = CONCAT('INSERT INTO `someTable` (`a`, `b`) VALUES (', a, ', ', b, ');');
    CALL sp_Log(l_errorMessage);
    LEAVE sp_label;
  END IF;

  SET c = 1;
END;

sp_Log只是将数据插入到我想用作我的logging table.

所以实际上内部的日志记录sp_A工作得很好(因为调用sp_Log在事务之外)但是内部的日志记录将不起作用,因为通过回滚开始的事务,通过调用内部sp_B或完成的插入当然会被恢复。sp_Csp_Asp_Logsp_Bsp_C

(我已经简化了示例, insp_Bsp_C。除了一个简单的插入语句之外,还有更多的事情发生,只是为了获得更多乐趣,还有事务开始并在sp_Band内提交/回滚sp_C。)

我会很感激你能给我的任何提示。谢谢!

4

1 回答 1

1

似乎解决此问题的一种可行方法是使用不支持事务的表引擎。在这种情况下,将日志表的表引擎从InnoDB更改为MyISAM解决问题。

于 2014-07-14T14:59:18.673 回答