简短版本: 如果有一个已启动的事务可能会回滚,那么如何将某些内容记录到日志表中?(事务的回滚也会回滚日志条目,这是这里的问题。)
长版:
我有一个存储过程,让我们调用它sp_A
来调用其他存储过程,让我们调用它们sp_B
和sp_C
. 为了一致性起见, anXA TRANSATCION
开始于sp_A
. 我真正想做的是记录执行sp_B
或sp_C
失败,如果是,哪些是传递给失败的存储过程的参数。但是,sp_B
在sp_C
某些表中进行一些插入操作时,我需要做一个XA ROLLBACK
ifsp_B
或sp_C
失败。
所以我的问题是:如何在事务中登录表(或如何在事务范围之外执行插入语句)?
给你一个我想做的小例子(我已经简化了代码并重命名了大多数用于解决问题的参数/变量,我永远不会梦想使用像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
或完成的插入当然会被恢复。sp_C
sp_A
sp_Log
sp_B
sp_C
(我已经简化了示例, insp_B
和sp_C
。除了一个简单的插入语句之外,还有更多的事情发生,只是为了获得更多乐趣,还有事务开始并在sp_B
and内提交/回滚sp_C
。)
我会很感激你能给我的任何提示。谢谢!