暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL的SQL语句 -条件处理语句(6) - 句柄的作用域规则

数据库杂货铺 2021-04-12
1152
句柄的作用域规则
 
存储程序可以包括程序中发生某些条件时要调用的句柄。每个句柄的适用性取决于其在程序定义中的位置及其处理的条件:
 
●  BEGIN ... END 块中声明的句柄仅在块中句柄声明之后的 SQL 语句的作用域中。如果句柄本身引发条件,则它无法处理该条件,块中声明的任何其他句柄也不能。在下面的示例中,句柄 H1 H2 在语句 stmt1 stmt2 引发的条件的作用域中。但 H1 H2 都不在 H1 H2 本身内出现的情况的范围内。
 
    BEGIN -- outer block
    DECLARE EXIT HANDLER FOR ...; -- handler H1
    DECLARE EXIT HANDLER FOR ...; -- handler H2
    stmt1;
    stmt2;
    END;
     
    ● 句柄只在声明它的块的作用域中,不能被块之外发生的条件下激活。在以下示例中,句柄 H1 在内部块的 stmt1 范围内,但不在外部块的 stmt2 范围内:
     
      BEGIN -- outer block
      BEGIN -- inner block
      DECLARE EXIT HANDLER FOR ...; -- handler H1
      stmt1;
      END;
      stmt2;
      END;
       
      ● 句柄可以是特定的,也可以是常规的。特定的句柄用于 MySQL 错误代码、SQLSTATE 值或条件名称。常规句柄用于 SQLWARNINGSQLEXCEPTION NOT FOUND 类中的条件。条件特征与条件优先级相关,如下文所述。
       
      可以在不同的作用域中声明具有不同特性的多个句柄。例如,在外部块中可能有一个特定的 MySQL 错误代码句柄,在内部块中可能有一个常规的 SQLWARNING 句柄。或者在同一块中可能有特定 MySQL 错误代码和常规 SQLWARNING 类的句柄。
       
      句柄是否被激活不仅取决于它自己的作用域和条件值,还取决于其他句柄的存在。当存储程序中出现条件时,服务器将在当前范围(当前 BEGIN ... END 块)搜索可用的句柄。如果没有适用的句柄,则继续向外搜索包含作用域(块)中的句柄。当服务器在给定的作用域中找到一个或多个适用的句柄时,它将根据条件优先级在其中进行选择:
       
      ● MySQL 错误代码句柄优先于 SQLSTATE 值句柄。
       
      ● SQLSTATE 值句柄优先于常规 SQLWARNINGSQLEXCEPTION NOT FOUND 句柄。
       
      ● SQLEXCEPTION 句柄优先于 SQLWARNING 句柄。
       
      ● 可以有几个具有相同优先级的适用句柄。例如,一条语句可以生成多个带有不同错误代码的警告,其中每个都有特定于错误的句柄。在这种情况下,服务器激活哪个句柄的选择是不确定的,并且可能会根据条件发生的环境而改变。
       
      句柄选择规则的一个含义是,如果多个适用的句柄出现在不同的作用域中,则具有最局部作用域的句柄优先于外部作用域中的句柄,甚至优先于更明确条件下的句柄。
       
      如果条件发生时没有适当的句柄,则所采取的操作取决于条件的类:
       
      ● 对于 SQLEXCEPTION 条件,存储程序在引发该条件的语句处终止,就好像存在一个 EXIT 句柄一样。如果程序被另一个存储程序调用,则调用程序将使用应用于自己的句柄的句柄选择规则来处理该条件。
       
      ● 对于 SQLWARNING 条件,程序将继续执行,就像有一个 CONTINUE 句柄一样。
       
      ● 对于 NOT FOUND 条件,如果条件正常引发,则操作为 CONTINUE。如果是通过 SIGNAL RESIGNAL 引发的,则操作是 EXIT
       
      下面的示例演示 MySQL 如何应用句柄选择规则。
       
      此过程包含两个句柄,一个用于尝试删除不存在的表时发生的特定 SQLSTATE 值('42S02'),另一个用于常规 SQLEXCEPTION 类:
       
        CREATE PROCEDURE p1()
        BEGIN
        DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
        SELECT 'SQLSTATE handler was activated' AS msg;
        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
        SELECT 'SQLEXCEPTION handler was activated' AS msg;


        DROP TABLE test.t;
        END;
         
        两个句柄都在同一块中声明,具有相同的作用域。但是,SQLSTATE 句柄优先于 SQLEXCEPTION 句柄,因此如果表 t 不存在,DROP TABLE 语句将引发激活 SQLSTATE 句柄的条件:
         
          mysql> CALL p1();
          +--------------------------------+
          | msg |
          +--------------------------------+
          | SQLSTATE handler was activated |
          +--------------------------------+
           
          此过程包含相同的两个句柄。但这一次,DROP TABLE 语句和 SQLEXCEPTION 句柄位于相对 SQLSTATE 句柄的内部块中:
           
            CREATE PROCEDURE p2()
            BEGIN -- outer block
            DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
            SELECT 'SQLSTATE handler was activated' AS msg;
            BEGIN -- inner block
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
            SELECT 'SQLEXCEPTION handler was activated' AS msg;


            DROP TABLE test.t; -- occurs within inner block
            END;
            END;
             
            在这种情况下,对条件发生的位置更为局部的句柄优先。SQLEXCEPTION 句柄激活,尽管它比 SQLSTATE 句柄更通用:
             
              mysql> CALL p2();
              +------------------------------------+
              | msg |
              +------------------------------------+
              | SQLEXCEPTION handler was activated |
              +------------------------------------+
               
              在此过程中,其中一个句柄在 DROP TABLE 语句作用域内的块中声明:
               
                CREATE PROCEDURE p3()
                BEGIN -- outer block
                DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
                SELECT 'SQLEXCEPTION handler was activated' AS msg;
                BEGIN -- inner block
                DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
                SELECT 'SQLSTATE handler was activated' AS msg;
                END;


                DROP TABLE test.t; -- occurs within outer block
                END;
                 
                只有 SQLEXCEPTION 句柄适用,因为另一个句柄不在 DROP TABLE 引发的条件的作用域内:
                 
                  mysql> CALL p3();
                  +------------------------------------+
                  | msg |
                  +------------------------------------+
                  | SQLEXCEPTION handler was activated |
                  +------------------------------------+
                   
                  在此过程中,两个句柄都在 DROP TABLE 语句作用域内的块中声明:
                   
                    CREATE PROCEDURE p4()
                    BEGIN -- outer block
                    BEGIN -- inner block
                    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
                    SELECT 'SQLEXCEPTION handler was activated' AS msg;
                    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
                    SELECT 'SQLSTATE handler was activated' AS msg;
                    END;


                    DROP TABLE test.t; -- occurs within outer block
                    END;
                     
                    这两个句柄都不适用,因为它们不在 DROP TABLE 的作用域中。语句引发的条件未经处理,并以错误终止过程:
                     
                      mysql> CALL p4();
                      ERROR 1051 (42S02): Unknown table 'test.t'
                       
                       
                       
                       
                       
                       
                      官方网址:
                      https://dev.mysql.com/doc/refman/8.0/en/handler-scope.html
                       

                      文章转载自数据库杂货铺,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论