MySQL定义异常和异常处理方法

<blockquote><p><strong>在存储过程或函数中,一定要主要异常处理的位置。通常放在DECLARE的最后,若存储过程有返回值,可通过类似如下方式解决:
</strong></p><p><strong>DECLARE EXIT HANDLER FOR SQLEXCEPTION </strong></p><p><strong>BEGIN</strong></p><p><strong>.....</strong></p><p><strong>SET @info='ERROR';</strong></p><p><strong>END;</strong></p></blockquote><p>在MySQL中,特定异常需要特定处理。这些异常可以联系到错误,以及子程序中的一般流程控制。定义异常是事先定义程序执行过程中遇到的问题,异常处理定义了在遇到问题时对应当采取的处理方式,并且保证存储过程或者函数在遇到错误时或者警告时能够继续执行。</p><h1>1 异常定义</h1><p><strong>1.1 语法</strong></p><p>DECLARE condition_name CONDITION FOR [condition_type];</p><p><strong>1.2 说明</strong></p><p><strong>condition_name</strong>参数表示异常的名称;</p><p><strong>condition_type</strong>参数表示条件的类型,condition_type由SQLSTATE [VALUE] sqlstate_value|<a>mysql</a>_error_code组成:</p><p>sqlstate_value和mysql_error_code都可以表示MySQL的错误;sqlstate_value为长度为5的字符串类型的错误代码;mysql_error_code为数值类型错误代码;</p><p><strong>1.3 示例</strong></p><p>定义“ERROR 1148(42000)”错误,名称为command_not_allowed。可以有以下两种方法:</p><p><strong>//</strong><strong>方法一:使用sqlstate_value</strong></p><p>DECLARE command_not_allowed CONDITION FOR SQLSTATE '42000';</p><p><strong>//</strong><strong>方法二:使用mysql_error_code</strong></p><p>DECLARE command_not_allowed CONDITION FOR 1148;</p><h1>2 自定义异常处理</h1><p><strong>2.1 异常处理语法</strong></p><p>DECLARE handler_type HANDLER FOR condition_value [,...] sp_statement</p><p><strong>2.2 参数说明</strong></p><p><strong>handler_type:</strong> CONTINUE|EXIT|UNDO</p><p>handler_type为错误处理方式,参数为3个值之一;CONTINUE表示遇到错误不处理,继续执行;EXIT表示遇到错误时马上退出;UNDO表示遇到错误后撤回之前的操作,MySQL暂不支持回滚操作;</p><p><strong>condition_value:</strong> SQLSTATE [VALUE] sqlstate_value| condition_name|SQLWARNING|NOT FOUND|SQLEXCEPTION|mysql_error_code</p><p>condition_value表示错误类型;SQLSTATE [VALUE] sqlstate_value为包含5个字符的字符串错误值;
condition_name表示DECLARE CONDITION定义的错误条件名称;SQLWARNING匹配所有以01开头的SQLSTATE错误代码;NOT FOUND匹配所有以02开头的SQLSTATE错误代码;SQLEXCEPTION匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码;mysql_error_code匹配数值类型错误代码;</p><p><strong>2.3 异常捕获方法</strong></p><p>//方法一:捕获sqlstate_value异常</p><p>//这种方法是捕获sqlstate_value值。如果遇到sqlstate_value值为"42S02",执行CONTINUE操作,并输出"NO_SUCH_TABLE"信息</p><p>DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='NO_SUCH_TABLE';</p><p>//方法二:捕获mysql_error_code异常</p><p>//这种方法是捕获mysql_error_code值。如果遇到mysql_error_code值为1146,执行CONTINUE操作,并输出"NO_SUCH_TABLE"信息;</p><p>DECLARE CONTINUE HANDLER FOR 1146 SET @info='NO_SUCH_TABLE';</p><p>//方法三:先定义条件,然后捕获异常</p><p>DECLARE no_such_table CONDITION FOR 1146;</p><p>DECLARE CONTINUE HANDLER FOR NO_SUCH_TABLE SET @info='NO_SUCH_TABLE';</p><p>//方法四:使用SQLWARNING捕获异常</p><p>DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';</p><p>//方法五:使用NOT FOUND捕获异常</p><p>DECLARE EXIT HANDLER FOR NOT FOUND SET @info='NO_SUCH_TABLE';</p><p>//方法六:使用SQLEXCEPTION捕获异常</p><p>DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';</p><h1>3 综合示例</h1><p><strong>创建一个表,设置该表的主键,在不定义异常处理和定义异常处理情况下看执行到哪一步。</strong></p><p><strong>show databases;</strong></p><p><strong>use wms;</strong></p><p><strong>create</strong> <strong>table</strong> <strong>location</strong></p><p><strong>(</strong></p><p><strong>location_id int</strong> <strong>primary</strong> <strong>key,</strong></p><p><strong>location_name varchar(50)</strong></p><p><strong>);</strong></p><p><strong>示例1:不定义异常情况下</strong></p><p><strong>DELIMITER //</strong></p><p><strong>CREATE</strong> <strong>PROCEDURE</strong> <strong>handlerInsertNoException()</strong></p><p><strong>BEGIN</strong></p><p><strong>    /DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2=1;/</strong></p><p><strong>    SET</strong> <strong>@x=1;</strong></p><p><strong>    INSERT</strong> <strong>INTO</strong> <strong>location VALUES</strong> <strong>(1,'Beijing');</strong></p><p><strong>    SET</strong> <strong>@x=2;</strong></p><p><strong>    INSERT</strong> <strong>INTO</strong> <strong>location VALUES</strong> <strong>(1,'Wuxi');</strong></p><p><strong>    SET</strong> <strong>@x=3;</strong></p><p><strong>END;</strong></p><p><strong>//</strong></p><p><strong>DELIMITER ;</strong></p><p>调用存储过程与结果:</p><p><strong>mysql> call handlerInsertNoException();</strong></p><p><strong>ERROR 1062 (23000): Duplicate entry '1'</strong> <strong>for</strong> <strong>key</strong> <strong>'PRIMARY'</strong></p><p><strong>mysql> select</strong> <strong>@x;</strong></p><p><strong>+------+</strong></p><p><strong>| @x   |</strong></p><p><strong>+------+</strong></p><p><strong>|    2 |</strong></p><p><strong>+------+</strong></p><p><strong>1 row in</strong> <strong>set</strong> <strong>(0.00 sec)</strong></p><p> </p><p><strong>mysql> select</strong> <strong>* from</strong> <strong>location;</strong></p><p><strong>+-------------+---------------+</strong></p><p><strong>| location_id | location_name |</strong></p><p><strong>+-------------+---------------+</strong></p><p><strong>|           1 | Beijing       |</strong></p><p><strong>+-------------+---------------+</strong></p><p><strong>1 row in</strong> <strong>set</strong> <strong>(0.00 sec)</strong></p><p>注意:操作示例2前要清空表中数据,并退出重新登录,以免客户端变量@x影响,详细说明参见结论中的第一点。</p><p><strong>mysql> truncate</strong> <strong>table</strong> <strong>location;</strong></p><p><strong>Query OK, 0 rows</strong> <strong>affected (0.04 sec)</strong></p><p><strong>mysql> select</strong> <strong>* from</strong> <strong>location;</strong></p><p><strong>Empty set</strong> <strong>(0.00 sec)</strong></p><p><strong>mysql> exit;</strong></p><p><strong>Bye</strong></p><p> </p><p><strong>david@Louis:~$ mysql -u root -p</strong></p><p><strong>Enter password:</strong></p><p><strong>Welcome to</strong> <strong>the MySQL monitor.  Commands end</strong> <strong>with</strong> <strong>; or</strong> <strong>\g.</strong></p><p><strong>Your MySQL connection</strong> <strong>id is</strong> <strong>53</strong></p><p><strong>Server version: 5.5.38-0ubuntu0.14.04.1 (Ubuntu)</strong></p><p> </p><p><strong>mysql> use wms;</strong></p><p><strong>Reading table</strong> <strong>information for</strong> <strong>completion of</strong> <strong>table</strong> <strong>and</strong> <strong>column</strong> <strong>names</strong></p><p><strong>You can turn off</strong> <strong>this feature to</strong> <strong>get a quicker startup with</strong> <strong>-A</strong></p><p> </p><p><strong>Database</strong> <strong>changed</strong></p><p><strong>mysql> select</strong> <strong>* from</strong> <strong>location;</strong></p><p><strong>Empty set</strong> <strong>(0.00 sec)</strong></p><p> </p><p><strong>mysql> select</strong> <strong>@x;</strong></p><p><strong>+------+</strong></p><p><strong>| @x   |</strong></p><p><strong>+------+</strong></p><p><strong>| NULL</strong> <strong>|</strong></p><p><strong>+------+</strong></p><p><strong>1 row in</strong> <strong>set</strong> <strong>(0.00 sec)</strong></p><p> </p><p><strong>示例2:定义异常处理情况下:</strong></p><p><strong>DELIMITER //</strong></p><p><strong>CREATE</strong> <strong>PROCEDURE</strong> <strong>handlerInsertWithException()</strong></p><p><strong>BEGIN</strong></p><p><strong>    DECLARE</strong> <strong>CONTINUE</strong> <strong>HANDLER FOR</strong> <strong>SQLSTATE '23000'</strong> <strong>SET</strong> <strong>@x2=1;</strong></p><p><strong>    SET</strong> <strong>@x=1;</strong></p><p><strong>    INSERT</strong> <strong>INTO</strong> <strong>location VALUES</strong> <strong>(1,'Beijing');</strong></p><p><strong>    SET</strong> <strong>@x=2;</strong></p><p><strong>    INSERT</strong> <strong>INTO</strong> <strong>location VALUES</strong> <strong>(1,'Wuxi');</strong></p><p><strong>    SET</strong> <strong>@x=3;</strong></p><p><strong>END;</strong></p><p><strong>//</strong></p><p><strong>DELIMITER ;</strong></p><p>
调用存储过程与结果:</p><p><strong>mysql> CALL handlerInsertWithException();</strong></p><p><strong>Query OK, 0 rows</strong> <strong>affected (0.09 sec)</strong></p><p> </p><p><strong>mysql> select</strong> <strong>@x;</strong></p><p><strong>+------+</strong></p><p><strong>| @x   |</strong></p><p><strong>+------+</strong></p><p><strong>|    3 |</strong></p><p><strong>+------+</strong></p><p><strong>1 row in</strong> <strong>set</strong> <strong>(0.00 sec)</strong></p><p> mysql> select @x,@x2//
+——+——+
| @x   | @x2  |
+——+——+
| 3    | 1    |
+——+——+
1 row in set (0.00 sec)
以上显示结果是@x=3,@x2=1,和上面分析的情况相同,说明程序运行无误。</p><p><strong>说明与结论:</strong></p><p>一、MySQL中,@var_name表示用户变量,使用SET语句为其赋值,用户变量与连接有关,一个客户端定义的变量不能被其他客户端看到或者使用。当客户端退出时,该客户端连接的所有变量将自动释放。</p><p>二、在示例1中,由于注释了异常的声明"",此时向表中插入相同主键,就会触发异常,并且采取默认(EXIT)路径;且查看此时的@x返回2,表示下面的INSERT语句并没有执行就退出了.</p><p>三、定义了异常处理,此时遇到错误也会按照异常定义那样继续执行;但只有第一条数据被插入到表中,此时用户变量@x=3说明已经执行到了结尾;</p><p><strong>DECLARE CONDITION</strong><strong>环境声明
</strong>    在进行错误处理的时候,可以使用SQLSTATE或指定一个错误代码,实际上,也可以给他们定义一个名字,然后在进行处理的时候使用定义的名字。比如看下面这个例子:
mysql> create procedure pro18()
    -> begin
    -> declareconstraint violation condition for sqlstate ’23000′;#注意constraint violation两侧的是“”,即Tab键上边,1键左边的按键,不是单引号,写成单引号会报错<br/>&nbsp;&nbsp;&nbsp; -&gt; declare exit handler forconstraint violationrollback;#注意constraint violation两侧的是“
    -> start transaction;
    -> insert into t2(s1) values(1);
    -> insert into t2(s1) values(1);
    -> commit;
    -> end;//
Query OK, 0 rows affected (0.00 sec)</p><p>首先给sqlstate ’23000′定义了一个名字constraint violation,在进行操作的时候,就直接可以用这个名字了。t2表是一个innodb表,所以对这个表的插入操作都会ROLLBACK回滚,在这 里例子中,由于主键插入两个同样的值导致sqlstate 23000错误发生,导致回滚事件发生。sqlstate 23000是约束错误。
    下面调用这个存储过程并查看运行结果:
mysql> call pro18()//
Query OK, 0 rows affected (0.04 sec)</p><p>mysql> select * from t2//
Empty set (0.01 sec)
    可以看到t2中没有插入任何记录,全部事务都回滚了。</p><p>     下面再来介绍几个声明条件,首先看例子:
mysql> create procedure pro19()
    -> begin
    -> declare exit handler for not found begin end;
    -> declare exit handler for sqlexception begin end;
    -> declare exit handler for sqlwarning begin end;
    -> end;//
Query OK, 0 rows affected (0.00 sec)
这个例子展示了三个预条件声明:NOT FOUNT是找不到行,SQLEXCEPTION是错误,SQLWARNING是警告或注释;这三个条件声明是预声明,所以不需要声明条件就可以使用。但 是如果使用:declare sqlexception condition….这种格式的话,就会报错。</p><p> </p><p>错误代码</p><p>
1011 HY000 Error on delete of ''%s'' (errn %d)
1021 HY000 Disk full (%s); waiting for someone to free some space . . .
1022 23000 Can''t write; duplicate key in table ''%s''
1027 HY000 ''%s'' is locked against change
1036 HY000 Table ''%s'' is read only
1048 23000 Column ''%s'' cannot be null
1062 23000 Duplicate entry ''%s'' for key %d
1099 HY000 Table ''%s'' was locked with a READ lock and can''t be updated
1100 HY000 Table ''%s'' was not locked with LOCK TABLES
1104 42000 The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay
1106 42000 Incorrect parameters to procedure ''%s''
1114 HY000 The table ''%s'' is full
1150 HY000 Delayed insert thread couldn''t get requested lock for table %s
1165 HY000 INSERT DELAYED can''t be used with table ''%s'' because it is locked with LOCK TABLES
1242 21000 Subquery returns more than 1 row
1263 22004 Column set to default value; NULL supplied to NOT NULL column ''%s'' at row %ld
1264 22003 Out of range value adjusted for column ''%s'' at row %ld
1265 1000 Data truncated for column ''%s'' at row %ld
1312 0A000 SELECT in a stored program must have INTO
1317 70100 Query execution was interrupted
1319 42000 Undefined CONDITION: %s
1325 24000 Cursor is already open
1326 24000 Cursor is not open
1328 HY000 Incorrect number of FETCH variables
1329 2000 No data to FETCH
1336 42000 USE is not allowed in a stored program
1337 42000 Variable or condition declaration after cursor or handler declaration
1338 42000 Cursor declaration after handler declaration
1339 20000 Case not found for CASE statement
1348 HY000 Column ''%s'' is not updatable
1357 HY000 Can''t drop a %s from within another stored routine
1358 HY000 GOTO is not allowed in a stored program handler
1362 HY000 Updating of %s row is not allowed in %s trigger
1363 HY000 There is no %s row in %s trigger </p><p>存储过程是<a>mysql</a>高级编程的一大特色,当然存储过程包括了很多的知识,包括错误处理,预定义等,下面让我们首先看一下错误处理的部分。</p><p><strong>定义错误:</strong></p><p>为错误定义一个名称,语法为:</p><pre>DECLARE error_name CONDITION FOR condition_value;</pre><pre>declare 定义一个变量</pre><pre>error_name:自定义的错误的名字</pre><pre>condition_value可以是两种情况:</pre><pre>第一:直接写错误号,如 1305;</pre><pre>
</pre><p>第二:写sqlstate错误号: 如</p><pre>SQLSTATE '42000';</pre><pre>
</pre><p><strong>错误处理</strong></p><p>语法为:</p><pre>DECLARE handler_type HANDLER FOR condition_value</pre><pre>begin</pre><pre>...</pre><pre>end;</pre><pre>handler_type: 处理的过程。</pre><pre>    CONTINUE 继续执行未完成的存储过程,直至结束。(常用,默认)</pre><pre>  | EXIT 出现错误即自动跳出所在的begin不再执行后面的语句。</pre><pre>condition_value: 处理的触发条件</pre><pre>    SQLSTATE [VALUE] sqlstate_value 不用说了,就是上面提到的第二中方法,也是最常用的错误定义,自己去查错误列表吧。</pre><pre>  | condition_name 我们刚刚定义的那个名字errorname就是用在这里的。</pre><pre>  | SQLWARNING 代表所有以01开头的错误代码</pre><pre>  | NOT FOUND 表所有以02开头的错误代码,当然也可以代表一个游标到达数据集的末尾。</pre><pre>  | SQLEXCEPTION 代表除了SQLWARNING和NOT FOUND 的所有错误代码。</pre><pre>  | mysql_error_code 错误编号,上面的第一种方法,不过同样可以在错误列表从中查到,是我比较常用的。</pre><pre> 
</pre><pre>例子:</pre><pre>create procedure error_test()</pre><pre>begin</pre><pre>#定义错误,1305是调用了错误的存储过程</pre><pre>declare errname condition for 1305;</pre><pre>declare continue handler for errname</pre><pre>begin</pre><pre>select 'no that procedure' as error;</pre><pre>end;</pre><pre>call aaa();end;</pre><pre>备注:</pre><pre>如果需要查看更多的错误列表可以直接到MySQL安装路径下。</pre><pre>比如我的/usr/local/mysql/share/mysql/errmsg.txt</pre><pre>说明:SQLSTATE [VALUE] sqlstate_value这种格式是专门为ANSI SQL 和 ODBC以及其他的标准.</pre><p>并不是所有的MySQL ERROR CODE 都映射到SQLSTATE。</p><p>
</p>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容