前面写了一些存储函数和存储过程,一直说其调试有难度,但是具体是否可以进行呢。所以在MYSQL通过定义条件和处理过程来解决这个问题。
定义条件:是事先定义程序执行过程中可能语句的问题
处理程序:定义了在遇到问题时应当采取的处理方式,并且保证存储过程或者函数在遇到错误或者警告能继续执行。
这样可以增加存储程序或函数处理问题的能力,避免程序异常停止运行。
其实这个如果用语言阐述的话,说实话我也会懵逼
# 首先创建一个表 然后插入数据CREATE TABLE test_1(t_id INT NOT NULL,t_name VARCHAR(10));INSERT INTO test_1 VALUES (1,'张三');INSERT INTO test_1 VALUES (1,'李四');
然后创建一个肯定会报错的的存储过程。
DELIMITER $CREATE PROCEDURE test1()BEGINSET @t_flag=1;UPDATE test_1 SET t_id=NULL WHERe t_name='张三';SET @t_flag=2;UPDATE test_1 SET t_id='22' WHERe t_name='张三';SET @t_flag=2;END $DELIMITER ;
然后调用存储函数
CALL test1();# 这个地方肯定会错的
不过这个时候补充一些,如果不用sqlyog而是用命令窗口的话会更加的详细。
然后查看一些@t_flag值。
select @t_flag;
这个可以看出存储过程执行后报错,但是通过定义的一个变量然后可以看出在UPDATE执行第一条语句的时候就报错了。
其实很多时候写存储过程调试的时候都是这样,因为这个很简单容易知道是哪里有错,但是很多时候报错就不知位置,所以不停的调试位置或者将后面的屏蔽掉进行一步一步的调试。
从这里又可以看出一件事在存储过程中未定义条件和处理程序,也就是当存储过程中执行的SQL报错时,MYSQL数据库就会抛出错误,并且退出当前SQL逻辑,不在执行存储过程中的后面语句。所以间的理解定义和处理程序就是有点像是自定义了一个JAVA中的try-catch语句。
定义条件定义条件就是给MYSQL中错误命名,这个有助于存储的程序代码更加清晰。它将一个错误名字和指定的错误条件关联起来,这个名字可以所有被定义在处理过程的DECLARE HANDLER语言中。
如果定义条件,格式如下:
DECLARE 错误名称 ConDITION FOR 错误码或者称之为条件
错误码的说明:
这个解释之前先看一下前面这个报错有两个数字1048和23000这个两个其实是两个不同的错误码:MYSQL_error_code和sqlstate_value;
MYSQL_error_code: 是数值类型错误代码。也就是:1048sqlstate_value: 是长度为5的字符串类型 的错误代码,也就是:‘23000’
其实这个两个都是代表的一种错误,都可以作为条件使用如下:
# 使用MYSQL_error_codeDECLARE Field_NOT_Is_Null ConDITION FOR 1048;#使用sqlstate_valueDECLARE Field_NOT_Is_Null ConDITION FOR SQLSTATE '23000';
定义处理程序这个就是为SQL执行过程中发生的某种类型的错误定义特殊的处理程序,定义处理程序时,使用DECLARE语句如下:
DECLARE 处理方式 HANDLER FOR 错误类型 处理语句
处理方式有三种:CONTINUE,EXIT和UNDO;
CONTINUE: 表示遇到错误不处理,继续执行,和JAVA中发for循环中的关键字意义差不多。EXIT:表示遇到错误就马上退出,这个点像是JAVA中的break的作用差不多。UNDO:表示语句错误后撤回之前的操作。但是有一句话要说可能又被骂,那就是MYSQL中目前不支持这样的操作。
错误类型:其实就是错误条件,其可以如下取值:
sqlstate_value: 也就是sqlstate中长度为5的错误的数值字符串MYSQL_error_code:匹配数组类型错误代码错误名称: 也就是前面定义的条件语句中DECLARE…CONDITION定义的错误条件名称。
这个可以看出既然出前面两个可以作为错误条件,拿为什么还要证明的一个,其实本质就是增加可读性,将一些错误数字用名称演示处理,读取存储函数或者存储过程时候更加便捷。
SQLWARNINT:匹配所有以01开头的sqlstate_value错误代码。NOT FOUND:匹配所有以02开头的sqlstate_value错误代码。SQLEXCEPTION:匹配所有不包含在SQLWARNINT和NOT FOUND中捕获的sqlstate_value错误代码。
处理语句:如果出现在上述条件中的一个,则采用对应的处理方式,并执行指定的处理语言。
语句可以像是前面设置@t_flag一样通过SET赋值,然后查询的@t_flag值就知道运行的情况了,也可以使用BEGIN…END编写的符号语句。
演示 案例1DELIMITER $CREATE PROCEDURE test2()BEGIN# 方式1DECLARE Field_NOT_Is_Null ConDITION FOR 1048;DECLARE EXIT HANDLER FOR Field_NOT_Is_Null SET @t_flag=-1;# 方式2#DECLARE EXIT HANDLER FOR 1048 SET @t_flag=1;# 方式3#DECLARE EXIT HANDLER FOR '23000' SET @t_flag=1;# SQLEXCEPTION 是以02和01开头之外的sqlstate#DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @t_flag=1;SET @t_flag=1;UPDATE test_1 SET t_id=NULL WHERe t_name='张三';SET @t_flag=2;UPDATE test_1 SET t_id='22' WHERe t_name='张三';SET @t_flag=2;END $DELIMITER ;
然后查看结果:
CALL test2();SELECT @t_flag;
案例2这个效果和案例1一样就是演示,就是如果语句多的话,可以用BEGIN…END作为一个模块,告诉后面都是满足这个条件后执行这个块里面的SQL语句。
DELIMITER $CREATE PROCEDURE test3()BEGINDECLARE Field_NOT_Is_Null ConDITION FOR 1048;DECLARE EXIT HANDLER FOR Field_NOT_Is_Null BEGIN SET @t_flag=-2; # 这个里面可以写很多其它的,但是这里只是一个演示END ; # 这个地方的结束符号还是继续使用;因为前面申请$为新的结束语句这个,如果用$等于这个存储过程的结束,所以用; SET @t_flag=1;UPDATE test_1 SET t_id=NULL WHERe t_name='张三';SET @t_flag=2;UPDATE test_1 SET t_id='22' WHERe t_name='张三';SET @t_flag=2;END $DELIMITER ;
现在看一下结果
CALL test3;SELECT @t_flag;