处理程序的范围规则
存储的程序可以包括在程序中发生某些条件时要调用的处理程序。每个处理程序的适用性取决于其在程序定义中的位置以及其处理的条件:
在
BEGIN ... END
块中声明的处理程序仅适用于该块中的处理程序声明之后的SQL语句。如果处理程序本身引发了一个条件,则它将无法处理该条件,该块中声明的任何其他处理程序也将无法处理。在以下示例中,处理程序H1
和H2
适用于语句stmt1
和引发的条件stmt2
。但是H1
也不H2
存在于H1
或体内提出的条件的范围H2
。BEGIN -- outer blockDECLARE EXIT HANDLER FOR ...; -- handler H1DECLARE EXIT HANDLER FOR ...; -- handler H2 stmt1; stmt2;END ;处理程序仅在声明它的块的范围内,并且对于该块外部发生的条件无法激活。在以下示例中,处理程序
H1
在stmt1
内部块的作用域中,而stmt2
在外部块的作用域中:BEGIN -- outer blockBEGIN -- inner blockDECLARE 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
处理程序。 - 可能有多个具有相同优先级的适用处理程序。例如,一条语句可能会生成带有不同错误代码的多个警告,每个警告代码都存在一个特定于错误的处理程序。在这种情况下,服务器激活哪个处理程序的选择是不确定的,并且可能会根据条件发生的情况而改变。
处理程序选择规则的一个含义是,如果多个适用的处理程序出现在不同的作用域中,则具有最局部作用域的处理程序将优先于外部作用域中的处理程序,甚至优先于更特定条件的处理程序。
如果条件发生时没有适当的处理程序,则采取的操作取决于条件的类:
- 对于
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 blockDECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'SELECT 'SQLSTATE handler was activated'AS msg;BEGIN -- inner blockDECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT 'SQLEXCEPTION handler was activated'AS msg;DROP TABLE test.t; -- occurs within inner blockEND ;END ;
在这种情况下,优先于发生条件的地方的处理程序。该SQLEXCEPTION
处理器激活,即使它是不是更一般的SQLSTATE
处理程序:
mysql>CALL p2(); +------------------------------------ + | msg | +------------------------------------ + | SQLEXCEPTION handler was activated | +------------------------------------ +
在此过程中,将在DROP TABLE
语句范围内的一个块中声明一个处理程序:
CREATE PROCEDURE p3()BEGIN -- outer blockDECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT 'SQLEXCEPTION handler was activated'AS msg;BEGIN -- inner blockDECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'SELECT 'SQLSTATE handler was activated'AS msg;END ;DROP TABLE test.t; -- occurs within outer blockEND ;
仅SQLEXCEPTION
处理程序适用,因为另一个处理程序不在以下条件引起的范围之内DROP TABLE
:
mysql>CALL p3(); +------------------------------------ + | msg | +------------------------------------ + | SQLEXCEPTION handler was activated | +------------------------------------ +
在此过程中,两个处理程序都在DROP TABLE
语句范围内的一个块中声明:
CREATE PROCEDURE p4()BEGIN -- outer blockBEGIN -- inner blockDECLARE 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 blockEND ;
这两个处理程序均不适用,因为它们不在的范围内DROP TABLE
。语句引发的条件无法处理,并以错误终止过程:
mysql>CALL p4(); ERROR 1051 (42S02): Unknown table 'test.t'