即使发生ROLLBACK,如何从MySQL中的存储过程中记录错误?

时间:2015-12-11 04:48:47

标签: mysql

我在MySQL的Store Procedure中有以下代码(见下文)。当我没有将所有内容都放在事务中时,我可以将Sproc上的错误直接记录到数据库中的表中。但是,当我在整个事情中放置一个START TRANSACTIONCOMMITROLLBACK时,我的日志记录将不再有效。我猜是因为它回滚了我的日志记录?我该如何解决这个问题?

DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    GET DIAGNOSTICS condition 1
    @SQLState = RETURNED_SQLSTATE, @SQLMessage = MESSAGE_TEXT; 
    SELECT CONCAT('Database error occurred, state - ',@SQLState, '; error msg - ', @SQLMessage) INTO @errorString;          

    CALL Log_Errors 
        (@errorString, 
        'MySprocName', 
        some_variable_1, 
        some_variable_2);

    ROLLBACK;
END;

START TRANSACTION;

-- do some stuff
-- error happens somewhere in here

COMMIT;

4 个答案:

答案 0 :(得分:1)

一种选择是使用MyISAM表进行日志记录。 MyISAM引擎不是事务性的。即使发出了ROLLBACK,插入到MyISAM表中的行也会保持插入状态。

将MyISAM用于日志记录表会引入一些其他限制。没有强制引用完整性(外键约束)。并且没有并发的DML操作。

答案 1 :(得分:1)

问题是陈旧的,但是对于谁需要答案,你必须在LOG之前调用ROLLBACK然后调用COMMIT:

DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    GET DIAGNOSTICS condition 1
    @SQLState = RETURNED_SQLSTATE, @SQLMessage = MESSAGE_TEXT; 
    SELECT CONCAT('Database error occurred, state - ',@SQLState, '; error msg - ', @SQLMessage) INTO @errorString;          

    ROLLBACK;
    CALL Log_Errors 
        (@errorString, 
        'MySprocName', 
        some_variable_1, 
        some_variable_2);
    COMMIT;
END;

START TRANSACTION;

-- do some stuff
-- error happens somewhere in here

COMMIT;

答案 2 :(得分:0)

退出时,只需执行SELECT并允许调用应用程序处理这样的日志记录:

DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    ...
    SELECT 
        CONCAT('Database error occurred, state - ',@SQLState, '; error msg - ', @SQLMessage) as @errorString,
        'MySprocName' as proc, 
        some_variable_1 as var1,  
        some_variable_2 as var2;

    ROLLBACK;
END;

START TRANSACTION;
-- do some stuff
COMMIT;

调用者PHP / Python /将捕获结果集并分析它的错误。如果发现错误,它将调用Log_Errors。这也将允许您在需要时登录文件系统。

答案 3 :(得分:0)

以下是回滚代码块的示例,该功能可以将错误记录到其他表中,而不会丢失MySQL中的异常详细信息,并在记录错误后再次抛出错误。您应该在回滚和记录部分之前(之后)进行诊断。

# CREATE PROCEDURE AND OTHER DECLARE STATEMENTS HERE
# ....

DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;

    ROLLBACK;

    SET @full_error = CONCAT('ERR:', @errno, '(', @sqlstate, '):', @text);

    CALL sp_logaction(@full_error); # Some logging procedure

    RESIGNAL; # Rethrow the error into the wild
END;
# PROCEDURE BODY WITH START TRANSACTION & COMMIT HERE
# .....