简短版本 如果有可能已回滚的已启动事务,如何将某些内容记录到日志表中? (回滚事务也会回滚日志条目,这是问题所在。)
长版:
我有一个存储过程,我们称之为sp_A
调用其他存储过程,让我们称它们为sp_B
和sp_C
。为了保持一致性,XA TRANSATCION
在sp_A
内启动。我真正想要做的是记录sp_B
或sp_C
的执行是否失败,如果是,则传递给失败的存储过程的参数。
但是,当sp_B
和sp_C
在某些表格中执行某些插入时,如果XA ROLLBACK
或sp_B
失败,我需要执行sp_C
。
所以我的问题是:我在交易中如何登录表格 (或如何在事务范围之外执行insert语句)?
为了给你一个我想要做的事情的例子(我已经简化了代码并重命名了大部分用于关注问题的参数/变量,我绝不会想到使用像{{这样的参数名称1}},a
或b
;-)):
存储过程c
如下所示:
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
内的日志记录赢得了&#39}。因为通过回滚在sp_C
中开始的交易,sp_A
或sp_Log
内sp_B
的调用所做的插入当然会被撤销。
(我在sp_C
和sp_B
中简化了示例。除了一个简单的插入语句之外还有更多内容,只是为了获得更多乐趣,有事务已启动并提交/回滚也在sp_C
和sp_B
内。)
我很感激你能给我的任何暗示。 谢谢!
答案 0 :(得分:1)
似乎解决此问题的一种可行方法是使用不支持事务的表引擎。在这种情况下,将日志表的表引擎从InnoDB
更改为MyISAM
解决了这个问题。