zoukankan      html  css  js  c++  java
  • mysql Error Handling and Raising in Stored Procedures

    MySQL的存储过程错误捕获方式和Oracle的有很大的不同。

    MySQL中可以使用DECLARE关键字来定义处理程序。其基本语法如下:

    DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement 
    
    handler_type: CONTINUE | EXIT  
    
    condition_value: 
    SQLSTATE [VALUE] sqlstate_value |
    condition_name | 
    SQLWARNING | 
    NOT FOUND  | 
    SQLEXCEPTION | 
    mysql_error_code 

    handler_type参数指明错误的处理方式,该参数有2个取值。这1个取值分别是CONTINUE、EXIT

    CONTINUE表示遇到错误,执行预先定义的方式,继续向下执行;

    EXIT表示遇到错误后,执行预先定义的方式,马上退出;

    注意:通常情况下,执行过程中遇到错误应该立刻停止执行下面的语句,并且撤回前面的操作。

    condition_value参数指明错误类型,该参数有6个取值。

    sqlstate_value和mysql_error_code与条件定义中的是同一个意思。

    condition_name是DECLARE定义的条件名称。

    SQLWARNING表示所有以01开头的sqlstate_value值。

    NOT FOUND表示所有以02开头的sqlstate_value值。

    SQLEXCEPTION表示所有没有被SQLWARNING或NOT FOUND捕获的sqlstate_value值。

    sp_statement表示一些存储过程或函数的执行语句。

    下面是定义处理程序的几种方式。代码如下:

    //方法一:捕获sqlstate_value 
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42000'
    SET @info='CAN NOT FIND'; 
    //方法二:捕获mysql_error_code 
    DECLARE CONTINUE HANDLER FOR 1148SET @info='CAN NOT FIND'; 
    //方法三:先定义条件,然后调用 
    DECLARE can_not_find CONDITION FOR 1146 ; 
    DECLARE CONTINUE HANDLER FOR can_not_find SET 
    @info='CAN NOT FIND'; 
    //方法四:使用SQLWARNING 
    DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR'; 
    //方法五:使用NOT FOUND 
    DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND'; 
    //方法六:使用SQLEXCEPTION 
    DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';

    上述代码是6种定义处理程序的方法。

    第一种方法是捕获sqlstate_value值。如果遇到sqlstate_value值为42000,执行CONTINUE操作,并且输出"CAN NOT FIND"信息。

    第二种方法是捕获mysql_error_code值。如果遇到mysql_error_code值为1148,执行CONTINUE操作,并且输出"CAN NOT FIND"信息。

    第三种方法是先定义条件,然后再调用条件。这里先定义can_not_find条件,遇到1148错误就执行CONTINUE操作。

    第四种方法是使用SQLWARNING。SQLWARNING捕获所有以01开头的sqlstate_value值,然后执行EXIT操作,并且输出"ERROR"信息。

    第五种方法是使用NOT FOUND。NOT FOUND捕获所有以02开头的sqlstate_value值,然后执行EXIT操作,并且输出"CAN NOT FIND"信息。

    第六种方法是使用SQLEXCEPTION。SQLEXCEPTION捕获所有没有被SQLWARNING或NOT FOUND捕获的sqlstate_value值。

    单句的

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_row_found = 1;
    DECLARE CONTINUE HANDLER FOR 1062
    SELECT 'Error, duplicate key occurred';

    如果错误捕获的时候要做的操作比较多可以这样

    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
    ROLLBACK;
    SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated';
    END;

    example:

    CREATE TABLE `article_tags` (
      `article_id` int(11) NOT NULL DEFAULT '0',
      `tag_id` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`article_id`,`tag_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    DELIMITER $$
     
    CREATE PROCEDURE insert_article_tags(IN article_id INT, IN tag_id INT)
    BEGIN
     
        DECLARE CONTINUE HANDLER FOR 1062
        SELECT CONCAT('duplicate keys (',article_id,',',tag_id,') found') AS msg;
     
        -- insert a new record into article_tags
        INSERT INTO article_tags(article_id,tag_id)
        VALUES(article_id,tag_id);
     
        -- return tag count for the article
        SELECT COUNT(*) FROM article_tags;
    END

    mysql 抛出错误给调用程序

    使用signal语句返回Error或warning给存储过程的调用者。

    signal的语法:

    SIGNAL SQLSTATE | condition_name
    SET condition_information_item_name_1 = value_1,
        condition_information_item_name_1 = value_2, etc;

    使用SET设置返回的内容,如果要返回多个条件信息用逗号隔开。

    RESIGNAL无论是功能上还是用法上和signal都很像,除了:

      1.使用resignal的时候必须配合handler使用,否则会得到 “RESIGNAL when handler is not active”的报错,

    然而signal可以在存储过程的任何地方使用。

      2.可以漏掉resignal语句的所有属性,甚至是SQLSTATE value.

    DELIMITER $$
     
    CREATE PROCEDURE AddOrderItem(
                     in orderNo int,
                 in productCode varchar(45),
                 in qty int, 
                             in price double, 
                             in lineNo int )
    BEGIN
        DECLARE C INT;
     
        SELECT COUNT(orderNumber) INTO C
        FROM orders 
        WHERE orderNumber = orderNo;
     
        -- check if orderNumber exists
        IF(C != 1) THEN 
            SIGNAL SQLSTATE '45000'
                SET MESSAGE_TEXT = 'Order No not found in orders table';
        END IF;
        -- more code below
        -- ...
    END
    DELIMITER $$
     
    CREATE PROCEDURE Divide(IN numerator INT, IN denominator INT, OUT result double)
    BEGIN
        DECLARE division_by_zero CONDITION FOR SQLSTATE '22012';
     
        DECLARE CONTINUE HANDLER FOR division_by_zero 
        RESIGNAL SET MESSAGE_TEXT = 'Division by zero / Denominator cannot be zero';
        -- 
        IF denominator = 0 THEN
            SIGNAL division_by_zero;
        ELSE
            SET result := numerator / denominator;
        END IF;
    END

    没有resignal 的时候调用存储过程:

    DELIMITER $$
    
    CREATE DEFINER=`root`@`localhost` PROCEDURE `insert_article_tags`(IN article_id INT, IN tag_id INT)
    BEGIN
     
         DECLARE CONTINUE HANDLER FOR 1062
            begin
            insert into pro_log values('1062',CONCAT('duplicate keys (',article_id,',',tag_id,') found'));
            SELECT CONCAT('duplicate keys (',article_id,',',tag_id,') found') AS msg;
        -- resignal set message_text ='duplicate keys';
            end ;
    
       -- declare continue handler for sqlexception
       -- SELECT 'SQLException invoked';
    
        -- insert a new record into article_tags
        INSERT INTO article_tags(article_id,tag_id)
        VALUES(article_id,tag_id);
     
        -- return tag count for the article
    SELECT 
        COUNT(*)
    FROM
        article_tags;
       
    END

    测试调用

     去掉注释的 resignal set。

    继续测试

    这样可以得到向外抛出的错误。

    参考:

    http://www.mysqltutorial.org/mysql-error-handling-in-stored-procedures/

    http://www.mysqltutorial.org/mysql-signal-resignal/

    http://www.cnblogs.com/lyhabc/p/3793524.html

    http://www.zhdba.com/mysqlops/2013/08/31/mysql-handler-2/

  • 相关阅读:
    延迟消失菜单
    控制产品上下滚动
    百度音乐全选
    百度文库评分两种代码写法
    选项卡
    搜狐视频
    m 调用传参图片切换
    IIS 7.5站点配置
    jquery plugins —— datatables 搜索后汇总
    jquery plugins —— datatables 增加行号
  • 原文地址:https://www.cnblogs.com/Alex-Zeng/p/3977971.html
Copyright © 2011-2022 走看看