阅读目录:存储过程的异常处理

    continue

    exit

    关于错误编号和SQLSTATE码

    使用3个处理程序

    忽略某一异常的处理

Q:何为异常?

A:程序在执行过程中有可能出错,运行时错误叫做异常。

默认情况下,当存储过程运行出错时,过程会立即终止,并打印系统错误消息。

实验环境:

mysql> use TENNIS
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A Database changed
mysql> show tables;
+-------------------+
| Tables_in_TENNIS |
+-------------------+
| COMMITTEE_MEMBERS |
| MATCHES |
| PENALTIES |
| PLAYERS |
| TEAMS |
+-------------------+
rows in set (0.00 sec)

因为前面的实验多数用此数据库,库表结构就不再赘述了。

例:创建过程,插入一个重复的2号球队

mysql> delimiter $$
mysql> create procedure duplicate_teams(
->   out p_processed smallint)
-> begin
->   set p_processed=;
->   insert into TEAMS values(,,'third');
->   set p_processed=;
-> end $$
mysql> delimiter ;
mysql> call duplicate_teams(@processed);
ERROR 1062 (23000): Duplicate entry '' for key 'PRIMARY'
mysql> select @processed;
+------------+
| @processed |
+------------+
| NULL |
+------------+

解析:客户端调用存储过程,运行出错,打印错误信息,过程被终止,没有输出。

一、定义异常处理:

DECLARE ... HANDLER语句:

  通过条件的定义和处理,可以在定义过程中,针对可能遇到的问题,做出相应的处理步骤。(也就是定义一个异常处理程序,指定当过程某条语句出错时,相应的采取什么操作)

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

注意:declare……handler语句必须出现在变量或条件声明的后面。

  当某个错误(condition_value)发生时--->执行指定的语句(statement--记录错误信息),执行完之后再决定如何操作(handler_action)。

  1、handler_action

    continue:继续执行当前的程序(接着执行出错的SQL的下一条语句);

    exit:当前程序终止(退出当前declare所在的begin end);

  目前还不支持undo功能。

  2、statement

    可以是单条语句或复合语句。

  3、condition_value指明handler被何种条件触发;如果条件被触发,却没有handler被声明用于处理该条件,程序的进行将取决于条件类型。

二、单个异常处理程序

  在输出参数中包含出错消息的SQLSTATE码。

例1:创建过程,插入一个重复的2号球队;continue

mysql> DELIMITER $$
mysql> CREATE PROCEDURE small_mistake1(
->   OUT error VARCHAR())
-> BEGIN
->   DECLARE CONTINUE HANDLER FOR SQLSTATE ''
->   SET error = ''; #用来记录错误发生时的一些信息
->
->   select error;
->   SET error = '';
->   select error;
-> INSERT INTO TEAMS VALUES(,,'third'); #会出错的语句
-> SET error = '';
-> END$$
mysql> DELIMITER ;
mysql> call small_mistake1(@a);
+-------+
| error |
+-------+
| NULL |
+-------+ +-------+
| error |
+-------+
| |
+-------+ mysql> select @a;
+-------+
| @a |
+-------+
| |
+-------+

实验示例解析:

  begin end块里,定义declare……handler语句用来捕获错误(待命ing),select、set、select顺序执行,insert语句出错,SQLSTATE码23000,捕获,进行异常处理(赋值记录),结束后会继续执行出错的insert语句的下一条语句……

例2:创建过程,插入一个重复的2号球队;exit

mysql> DELIMITER $$
mysql> CREATE PROCEDURE small_mistake2(
->   OUT error VARCHAR())
-> BEGIN
->   DECLARE EXIT HANDLER FOR SQLSTATE ''
->   SET error = '';
->
->   select error;
->   SET error = '';
->   select error;
->   INSERT INTO TEAMS VALUES(,,'third');
->   SET error = '';
-> END$$
mysql> DELIMITER ;
mysql> call small_mistake2(@a);
+-------+
| error |
+-------+
| NULL |
+-------+ +-------+
| error |
+-------+
| |
+-------+ mysql> select @a;
+-------+
| @a |
+-------+
| |
+-------+

与例1唯一不同的是:handler_action选择的是exit,表明在异常处理结束后不会继续执行错误语句后面的语句,直接退出begin end语句块。

三、多个异常处理程序

  可以在一个过程中定义多个异常处理程序,针对不同的错误进行不同的处理。

例1:

mysql> INSERT INTO TEAMS VALUES(,,'third',);
ERROR (21S01): Column count doesn't match value count at row 1 mysql> DELIMITER $$
mysql> CREATE PROCEDURE small_mistake3(
->   OUT error VARCHAR())
-> BEGIN
->   DECLARE CONTINUE HANDLER FOR SQLSTATE ''
->   SET error = '';
->
->   DECLARE CONTINUE HANDLER FOR SQLSTATE '21S01'
->   SET error = '21S01';
->
->   INSERT INTO TEAMS VALUES(,,'third',); #错误语句
-> END$$
mysql> DELIMITER ;
mysql> call small_mistake3(@error);
mysql> select @error;
+--------+
| @error |
+--------+
| 21S01 |
+--------+

解析:

  如果SQLSTATE码是23000,异常处理执行SET error = '23000';

  如果SQLSTATE码是21S01,异常处理执行SET error = '21S01';

当然,异常处理,可以是自定义,一般都是上述方式的错误信息记录。

示例3中的异常处理程序也可以使用错误编号

例如:

DECLARE CONTINUE HANDLER FOR
SET error = ''; DECLARE CONTINUE HANDLER FOR
SET error = '21S01';

关于错误编号和SQLSTATE码:

  每个MySQL错误都有一个唯一的数字错误编号(mysql_error_code),每个错误又对应一个5字符的SQLSTATE码(ANSI SQL 采用)。

SQLSTATE码对应的处理程序:

  1、SQLWARNING处理程序:以‘01’开头的所有sqlstate码与之对应;

  2、NOT FOUND处理程序:以‘02’开头的所有sqlstate码与之对应;

  3、SQLEXCEPTION处理程序:不以‘01’或‘02’开头的所有sqlstate码,也就是所有未被SQLWARNING或NOT FOUND捕获的SQLSTATE(常遇到的MySQL错误就是非‘01’、‘02’开头的)

注意:‘01’、‘02’开头和‘1’、‘2’开头是有区别的,是不一样的错误sqlsate码。

当不想为每个错误都定义一个处理程序时,可以使用3个处理程序

  e.g:DECLARE CONTINUE HANDLER FOR SQLWARNING,NOT FOUND,SQLEXCEPTION

mysql> DELIMITER $$
mysql> CREATE PROCEDURE small_mistake4(
->   OUT error VARCHAR())
-> BEGIN
->   DECLARE CONTINUE HANDLER FOR SQLWARNING,NOT FOUND,SQLEXCEPTION
->   SET error = 'xxxxx';
->
->   INSERT INTO teams VALUES(,,'third');
-> END$$
mysql> DELIMITER ;
mysql> call small_mistake4(@a);
mysql> select @a;
+-------+
| @a |
+-------+
| xxxxx |
+-------+

如果是在定义处理程序时,想忽略某一个条件

e.g:DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

也就是说,当遇到SQLWARNING的问题时,进行的异常处理是begin end块,因为里面什么都没有,就类同于直接忽略。

四、异常处理的命名

  为了提高可读性,可以给某个sqlstate代码或mysql错误代码一个名字,并且在后面的异常处理程序中使用这个名字。

DECLARE condition_name CONDITION FOR condition_value

condition_value:
mysql_error_code
|SQLSTATE [VALUE] sqlstate_value

1、未命名的基本格式:

BEGIN
  DECLARE CONTINUE HANDLER FOR
-- body of handler
END;

2、有命名的基本格式:

BEGIN
  DECLARE no_such_table CONDITION FOR ;
  DECLARE CONTINUE HANDLER FOR no_such_table
-- body of handler
END;
mysql> DELIMITER $$
mysql> CREATE PROCEDURE small_mistake5(
->   OUT error VARCHAR())
-> BEGIN
->   DECLARE non_unique CONDITION FOR SQLSTATE '';
->   DECLARE CONTINUE HANDLER FOR non_unique
->   begin
->     SET error = '';
->     select error;
->   end;
->
->   INSERT INTO TEAMS VALUES(,,'third'); #会出错语句
-> END$$
mysql> DELIMITER ;
mysql> call small_mistake5(@error);
+-------+
| error |
+-------+
| |
+-------+

五、异常传播

  在嵌套块的情况下,内部块中发生异常了,首先由本块的异常处理程序来处理,如果本块没有处理,则由外部块的异常处理程序来处理。

mysql> DELIMITER $$
mysql> CREATE PROCEDURE small_mistake6()
-> BEGIN
->   DECLARE CONTINUE HANDLER FOR SQLSTATE ''
->   SET @processed = ;
->
->   BEGIN
->     DECLARE CONTINUE HANDLER FOR SQLSTATE ''
->     SET @processed = ;
->     INSERT INTO TEAMS VALUES(,,'third');
->     set @test=;
-> END;
-> END$$
mysql> DELIMITER ;
mysql> call small_mistake6;
mysql> select @processed,@test;
+------------+--------+
| @processed | @test |
+------------+--------+
| | |
+------------+--------+

解析:@processed=100说明内部块里的异常传播到了外部块,交由外部块的异常处理程序进行的处理。

墙裂建议:

  当有多层begin end的时候,每层都应该有自己完善的异常处理,做到:自己的异常,自己这层去处理。

MySQL存储过程的异常处理的更多相关文章

  1. mysql存储过程之异常处理篇

    mysql存储过程也提供了对异常处理的功能:通过定义HANDLER来完成异常声明的实现 语法如下: DECLARE handler_type HANDLER FOR condition_value[, ...

  2. 详解MySQL存储过程的“异常处理”

    阅读目录:存储过程的异常处理 定义异常处理 单一异常处理程序 continue exit 多个异常处理程序 关于错误编号和SQLSTATE码 使用3个处理程序 忽略某一异常的处理 异常处理的命名 异常 ...

  3. MySQL 存储过程的异常处理

    mysql> mysql> delimiter $$ mysql> mysql> CREATE PROCEDURE myProc     ->     (p_first_ ...

  4. MySQL存储过程学习笔记

    MySQL在5.0以前并不支持存储过程,这使得MySQL在应用上大打折扣.MySQL 5.0终于开始支持存储过程了. MySQL的关键字大小写通用.该学习笔记对关键字使用大写:变量名,表名使用小写. ...

  5. MYSQL 存储过程 多表更新异常捕捉和异常处理方式

    今天在做MYSQL 存储过程 多表更新的功能   多表更新时候注意事项 1.首先是确保多表更新能够一次执行,途中没有哪个表的sql语句错误 2.上线后修改表结构及字段,请注意检查是否影响mysql 过 ...

  6. MySQL存储过程(转)

    一.MySQL 创建存储过程 "pr_add" 是个简单的 MySQL 存储过程,这个存储过程有两个 int 类型的输入参数 "a"."b" ...

  7. MySql存储过程

    MySQL 存储过程 ```sql CREATE PROCEDURE myprocedure (IN para01 INTEGER) BEGIN DECLARE var01 CHAR(10); IF ...

  8. mysql存储过程之游标遍历数据表

    原文:mysql存储过程之游标遍历数据表 今天写一个mysql存储过程,根据自己的需求要遍历一个数据表,因为对存储过程用的不多,语法不甚熟悉,加之存储过程没有调试环境,花了不少时间才慢慢弄好,故留个痕 ...

  9. MySQL 存储过程 经常使用语法

    MySQL 存储过程是从 MySQL 5.0 開始添加的新功能.存储过程的长处有一箩筐.只是最基本的还是运行效率和SQL 代码封装.特别是 SQL 代码封装功能,假设没有存储过程,在外部程序訪问数据库 ...

随机推荐

  1. String.valueOf 的坑

    一个方法返回 null,如果使用 String.valueOf() 进行转换,则会将 null 转为字符串 "null". 前者是个空类型,后者则是包含四个字母(n,u,l,l)的 ...

  2. Servlet 全局验证是否登录

    Java过滤器的使用和拦截排除的实现 http://blog.csdn.net/kyunchen/article/details/52187514

  3. Keil C 中全局变量 extern 的使用

    在KEIL C中,有多个源文件使用到全局变量时,可以在一个源文件中定义全局变量,在另外的源文件中用extern 声明该变量,说明该变量定义在别的文件中,将其作用域扩展到此文件. 例如:有以下两个源文件 ...

  4. R语言:变量名称和字符串的转换

    R语言:变量名称和字符串的转换 2014-06-23 14:45:27         在R语言中,经常会遇到变量名称和字符串相互转换的问题.比如说,进行1000次循环运算,并将运算结果存储在1000 ...

  5. 第三百三十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—深度优先与广度优先原理

    第三百三十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—深度优先与广度优先原理 网站树形结构 深度优先 是从左到右深度进行爬取的,以深度为准则从左到右的执行(递归方式实现)Scrapy默认 ...

  6. e788. 取消JSpinner的键盘编辑能力

    // Create a nummber spinner JSpinner spinner = new JSpinner(); // Disable keyboard edits in the spin ...

  7. 在Eclipse中设置进行JNI的头文件编译方法(转 http://blog.csdn.net/mirkerson/article/details/17187109)

    这两天在搞NDK开发,JNI的头文件进行编译的时候,要跑到对应的class文件路径下(通常是工程的bin目录),进行编译生成,很是不便,也容易出错,所以考虑在Eclipse中作为外部工具引入,所以便查 ...

  8. js sendBeacon

    页面性能日志: DNS解析耗时 TCP链接耗时 SSL安全链接耗时 网络请求耗时 DOM解析耗时 资源加载耗时 首包时间 白屏时间 首次可交换时间 Dom Ready时间 页面完全加载时间. 如某些统 ...

  9. 【玩转Golang】reflect.DeepEqual

    如果有两个map,内容都一样,只有顺序不同 m1:=map[,,}; m2:=map[,,}; 我们怎么判断二者是否一致呢? 如果你打算这么写: fmt.Println("m1==m2&qu ...

  10. cordova开发跨平台应用问题随笔记

    iOS下频繁请求地理位置授权 做的某个cordova应用有用到geolocation插件,跑在iOS的时候发现app请求了一次授权,结果webkit还请求了一次授权,不但如此,webkit请求的格式还 ...