【问题标题】:How to Store MySQL Trigger exception / failure info into Table or in Variables如何将 MySQL 触发器异常/失败信息存储到表或变量中
【发布时间】:2016-10-07 10:05:59
【问题描述】:

我被困在某个地方,我需要你的帮助。

场景

我有两个数据库,即 test_db1test_db2 并在它们上都有 users 表。两个数据库最初都是空的(0 行)。

这是users 表架构:

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(11) AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

之后,我在test_db1.users 表上为INSERTUPDATEDELETE 事件编写了一些触发器,下面是每个触发器的作用:

  • INSERTtest_db1.users 中,在test_db2.users 中插入同一行
  • UPDATEtest_db1.users,更新test_db2.users 中的同一行
  • DELETEtest_db1.users 上,从test_db2.users 中删除同一行

这里是触发代码sn-p。

DELIMITER //

-- TRIGGER FOR INSERT
DROP TRIGGER IF EXISTS `test_db1_users_bi`;
CREATE TRIGGER `test_db1_users_bi` BEFORE INSERT ON `users` FOR EACH ROW 
BEGIN
    INSERT INTO `test_db2`.`users` (id, name, age) VALUES (NEW.id, NEW.name, NEW.age);
END; //

-- TRIGGER FOR UPDATE
DROP TRIGGER IF EXISTS `test_db1_users_bu`;
CREATE TRIGGER `test_db1_users_bu` BEFORE UPDATE ON `users` FOR EACH ROW 
BEGIN
    UPDATE `test_db2`.`users`
        SET name = NEW.name,
            age = NEW.age
        WHERE id = NEW.id;
END; //

-- TRIGGER FOR DELETE
DROP TRIGGER IF EXISTS `test_db1_users_bd`;
CREATE TRIGGER `test_db1_users_bd` BEFORE DELETE ON `users` FOR EACH ROW 
BEGIN
    DELETE FROM `test_db2`.`users`
        WHERE id = OLD.id;
END; //

-- DELIMITER;

现在,问题来了!

目前,这没有在触发器中定义任何错误/异常处理程序。所以,我也想处理它,但我不知道该怎么做。我只是不知道如何获取异常以及异常等属性 - 错误代码、错误消息?

我只想将捕获的异常/错误从每个触发器存储到test_db1.errors 表中(如果失败):

这是errors 表架构,如下所示:

DROP TABLE IF EXISTS `errors`;
CREATE TABLE `errors` (
  `id` int(11) AUTO_INCREMENT,
  `error_code` varchar(30) DEFAULT NULL,
  `error_message` TEXT DEFAULT NULL,
  `emailed` TINYINT DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

仅供参考:以下是可能的故障:

  • 如果test_db2 不存在或无法连接?
  • 如果INSERT 触发器失败,即,无论是什么原因?
  • 如果UPDATE 触发器失败,即无论是什么原因?
  • 如果DELETE 触发器失败,即,无论是什么原因?

如果有人可以告诉我如何获取异常及其属性,如错误代码、错误消息并将其存储到触发器内部的变量中,以便我执行插入以将它们存储到表中?

我正在运行 MySQL 版本:5.5+

谢谢!

【问题讨论】:

标签: mysql database triggers


【解决方案1】:

我通过DECLARE CONTINUE HANDLERGET DIAGNOSTICS CONDITION 发现了一个hack,所以我想,我必须在这里分享。

这是我完整的最终脚本,它为两个数据库users 表保持备份(同步)这意味着test_db1(我们可以称之为生产数据库)上的任何更新都将发生在test_db2(其中我们可以称它为 stagingDB):

/*
Create two databases:
    1. `test_db1`
    2. `test_db2`
and execute below create *Table script* on both databases.
after that execute *Triggers Script* on `test_db1` only..
*/

/*
    TABLE STRUCTURE FOR `users`
*/

DROP TABLE IF EXISTS `users`;
CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) AUTO_INCREMENT NOT NULL,
  `name` varchar(30) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

/*
    TABLE STRUCTURE FOR `errors`
*/

DROP TABLE IF EXISTS `errors`;
CREATE TABLE IF NOT EXISTS `errors` (
  `id` int(11) AUTO_INCREMENT NOT NULL,
  `code` varchar(30) NOT NULL,
  `message` TEXT NOT NULL,
  `query_type` varchar(50) NOT NULL,
  `record_id` int(11) NOT NULL,
  `on_db` varchar(50) NOT NULL,
  `on_table` varchar(50) NOT NULL,
  `emailed` TINYINT DEFAULT 0,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

/*
    TRIGGERS SCRIPTS FOR INSERT, UPDATE AND DELETE OPERATIONS
*/

DELIMITER //

-- TRIGGER FOR INSERT
DROP TRIGGER IF EXISTS `test_db1_users_ai`;
CREATE TRIGGER `test_db1_users_ai` AFTER INSERT ON `users` FOR EACH ROW 
BEGIN
    -- Declare variables to hold diagnostics area information
    DECLARE errorCode CHAR(5) DEFAULT '00000';
    DECLARE errorMessage TEXT DEFAULT '';

    -- Declare exception handler for failed insert
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
    BEGIN
      GET DIAGNOSTICS CONDITION 1
        errorCode = RETURNED_SQLSTATE, errorMessage = MESSAGE_TEXT;
    END;

    -- Perform the insert
    INSERT INTO `test_db2`.`users` (id, name, age) VALUES (NEW.id, NEW.name, NEW.age);

    -- Check whether the insert was successful
    IF errorCode != '00000' THEN
        INSERT INTO `errors` (code, message, query_type, record_id, on_db, on_table) VALUES (errorCode, errorMessage, 'insert', NEW.id, 'test_db2', 'users');
    END IF;
END; //

-- TRIGGER FOR UPDATE
DROP TRIGGER IF EXISTS `test_db1_users_au`;
CREATE TRIGGER `test_db1_users_au` AFTER UPDATE ON `users` FOR EACH ROW 
BEGIN
    -- Declare variables to hold diagnostics area information
    DECLARE errorCode CHAR(5) DEFAULT '00000';
    DECLARE errorMessage TEXT DEFAULT '';

    -- Declare exception handler for failed insert
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
    BEGIN
      GET DIAGNOSTICS CONDITION 1
        errorCode = RETURNED_SQLSTATE, errorMessage = MESSAGE_TEXT;
    END;

    -- Perform the update
    UPDATE `test_db2`.`users`
        SET name = NEW.name,
            age = NEW.age
        WHERE id = NEW.id;

    -- Check whether the update was successful
    IF errorCode != '00000' THEN
        INSERT INTO `errors` (code, message, query_type, record_id, on_db, on_table) VALUES (errorCode, errorMessage, 'update', NEW.id, 'test_db2', 'users');
    END IF;
END; //

-- TRIGGER FOR DELETE
DROP TRIGGER IF EXISTS `test_db1_users_ad`;
CREATE TRIGGER `test_db1_users_ad` AFTER DELETE ON `users` FOR EACH ROW 
BEGIN
    -- Declare variables to hold diagnostics area information
    DECLARE errorCode CHAR(5) DEFAULT '00000';
    DECLARE errorMessage TEXT DEFAULT '';

    -- Declare exception handler for failed insert
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
    BEGIN
      GET DIAGNOSTICS CONDITION 1
        errorCode = RETURNED_SQLSTATE, errorMessage = MESSAGE_TEXT;
    END;

    -- Perform the delete
    DELETE FROM `test_db2`.`users`
        WHERE id = OLD.id;

    -- Check whether the insert was successful
    IF errorCode != '00000' THEN
        INSERT INTO `errors` (code, message, query_type, record_id, on_db, on_table) VALUES (errorCode, errorMessage, 'delete', OLD.id, 'test_db2', 'users');
    END IF;
END; //

-- DELIMITER;

希望其他人来这里时会有所帮助。

干杯,

【讨论】:

    【解决方案2】:

    查看 DECLARE HANDLER 的语法

    http://dev.mysql.com/doc/refman/5.1/en/declare-handler.html

    另外,如果您尝试调试 SP,这可能对您有所帮助:

    http://www.bluegecko.net/mysql/debugging-stored-procedures/

    触发后,您可以使用以下内容:

        CREATE TRIGGER `my_table_AINS` AFTER INSERT ON `my_table` FOR EACH ROW
    BEGIN
        DECLARE EXIT HANDLER FOR SQLEXCEPTION
            RESIGNAL;
        DECLARE EXIT HANDLER FOR SQLWARNING
            RESIGNAL;
        DECLARE EXIT HANDLER FOR NOT FOUND
            RESIGNAL; 
        -- Do the work of the trigger.
    END
    

    希望这对您有所帮助。

    【讨论】:

    • 那个 RESIGNAL 是做什么的?我想将异常/警告/错误代码和消息存储到表中.. ?
    • 没有得到..刚刚尝试了文档中给出的示例,但似乎不起作用。
    【解决方案3】:

    这看起来像主从服务器/数据库场景。您可以查看二进制日志记录。因此,主服务器中的任何操作都将被记录为一个事件,并且同样适用于从服务器。 Checkout MySQL official reference

    【讨论】:

      猜你喜欢
      • 2010-09-24
      • 1970-01-01
      • 2015-12-27
      • 2011-10-27
      • 2020-04-20
      • 2012-01-26
      • 2023-04-03
      • 1970-01-01
      • 2023-01-11
      相关资源
      最近更新 更多