如何在事务中封装的存储过程中进行日志记录

时间:2014-07-07 08:13:28

标签: mysql stored-procedures transactions mysql-5.5

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

长版:

我有一个存储过程,我们称之为sp_A调用其他存储过程,让我们称它们为sp_Bsp_C。为了保持一致性,XA TRANSATCIONsp_A内启动。我真正想要做的是记录sp_Bsp_C的执行是否失败,如果是,则传递给失败的存储过程的参数。 但是,当sp_Bsp_C在某些表格中执行某些插入时,如果XA ROLLBACKsp_B失败,我需要执行sp_C

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

为了给你一个我想要做的事情的例子(我已经简化了代码并重命名了大部分用于关注问题的参数/变量,我绝不会想到使用像{{这样的参数名称1}},ab ;-)):

存储过程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_Logsp_B内的日志记录赢得了&#39}。因为通过回滚在sp_C中开始的交易,sp_Asp_Logsp_B的调用所做的插入当然会被撤销。

(我在sp_Csp_B中简化了示例。除了一个简单的插入语句之外还有更多内容,只是为了获得更多乐趣,有事务已启动并提交/回滚也在sp_Csp_B内。)

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

1 个答案:

答案 0 :(得分:1)

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