存储的程序可以包括处理程序,当程序中出现某些条件时将调用该处理程序。每个处理程序的适用性取决于它在程序定义中的位置以及它处理的一个或多个条件:
在
BEGIN ... END
块中声明的处理程序仅在块中处理程序声明之后的 SQL 语句的范围内。如果处理程序本身引发条件,则它无法处理该条件,块中声明的任何其他处理程序也无法处理。在以下示例中,处理程序H1
和 在语句和H2
引发的条件范围内。但是 nor都不在 or正文中提出的条件的范围内。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
值或条件名称。通用处理程序用于 、 或 类中SQLWARNING
的SQLEXCEPTION
条件NOT FOUND
。条件特异性与条件优先级有关,如后所述。
可以在不同的范围内声明多个处理程序并具有不同的特性。例如,外部块中可能有一个特定的 MySQL 错误代码处理
SQLWARNING
程序,内部块中可能有一个通用处理程序。SQLWARNING
或者在同一个块中
可能有针对特定 MySQL 错误代码和通用类的处理程序。
处理程序是否被激活不仅取决于它自己的范围和条件值,还取决于存在的其他处理程序。BEGIN ...
END
当存储程序中出现条件时,服务器会在当前范围(当前块)中搜索适用的处理程序
。如果没有适用的处理程序,则继续向外搜索每个连续包含范围(块)中的处理程序。当服务器在给定范围内找到一个或多个适用的处理程序时,它会根据条件优先级在其中进行选择:
MySQL 错误代码处理程序优先于
SQLSTATE
值处理程序。SQLSTATE
值处理程序优先于一般 的SQLWARNING
、SQLEXCEPTION
或NOT FOUND
处理程序。SQLEXCEPTION
处理程序优先于 处理SQLWARNING
程序。可以有多个具有相同优先级的适用处理程序。例如,一条语句可以生成多个具有不同错误代码的警告,每个错误代码都存在一个特定于错误的处理程序。在这种情况下,服务器激活哪个处理程序的选择是不确定的,并且可能会根据条件发生的情况而改变。
处理程序选择规则的一个含义是,如果多个适用的处理程序出现在不同的范围内,则具有最本地范围的处理程序优先于外部范围中的处理程序,甚至超过那些更具体条件的处理程序。
如果在条件发生时没有合适的处理程序,则采取的操作取决于条件的类别:
以下示例演示了 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'