mysql之存儲過程(三)(異常處理)

異常處理

程序在執行過程中有可能出錯。運行時錯誤叫做異常
默認情況下,當過程運行出錯時,過程會立即終止,並打印系統錯誤消息

沒有異常處理的存儲過程,執行過程中非常難以預測執行結果,所以儘量存儲過程中加上異常處理部分。

注意:
1、異常後面的第一條SQL語句(也可以是begin end)與異常是一起的,他們一起執行。
2、一開始執行語句時不執行異常處理部分,執行到報錯的地方時,跳到異常處理的地方,如果能捕獲就執行異常處理部分,不能捕獲就不執行異常處理部分。執行完異常處理部分有兩個選擇continue、exit。

案例
1、

DELIMITER $$
CREATE  PROCEDURE duplicate_teams(  
    OUT  p_processed  SMALLINT)   
 BEGIN     
   SET  p_processed = 1;
   INSERT INTO TEAMS VALUES(2,27,'third');
   SET  p_processed = 2;           
 END$$
DELIMITER ;
mysql> CALL duplicate_teams(@processed);
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'

2、

DELIMITER $$

CREATE  PROCEDURE small_mistake1(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'  
     SET error = '23000';  
     select error;
     SET error = '00000';
     select error;
   INSERT INTO TEAMS VALUES(2,27,'third');
   SET error = '23001';      
 END$$

DELIMITER ;
mysql> call small_mistake1(@a);
+-------+
| error |
+-------+
| NULL  |
+-------+
| error |
+-------+
| 00000 |
mysql> select @a;
+-------+
| @a    |
+-------+
| 23001 |

異常處理中的SQL語句,一般用來記錄錯誤發生時的一些信息。
3、

delimiter $$

CREATE PROCEDURE handlerdemo ()
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
  SET @x = 1;
  INSERT INTO test.t VALUES (1);
  SET @x = 2;
  INSERT INTO test.t VALUES (1);
  SET @x = 3;
END$$
delimiter ;

CALL handlerdemo()
mysql> select @x2;
+------+
| @x2  |
+------+
|    1 |
mysql> select @x;
+------+
| @x   |
+------+
|    3 |

4、

DELIMITER $$

CREATE  PROCEDURE small_mistake2(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE EXIT HANDLER FOR SQLSTATE '23000'  
     SET error = '23000';   
     select error;
     SET error = '00000';
     select error;
   INSERT INTO TEAMS VALUES(2,27,'third');
   SET error = '23001';      
 END$$

DELIMITER ;
mysql> call small_mistake2(@a);
| error |
+-------+
| NULL  |
+-------+
| error |
+-------+
| 00000 |
mysql> select @a;
+-------+
| @a    |
+-------+
| 23000 |

例15:創建過程,插入一個重複的2號球隊

DELIMITER $$

CREATE  PROCEDURE duplicate_teams(  
    OUT  p_processed  SMALLINT)   
 BEGIN     
   SET  p_processed = 1;
   INSERT INTO teams VALUES(2,27,'third');
   SET  p_processed = 2;           
 END$$

DELIMITER ;
客戶端調用:
CALL duplicate_teams(@processed);

異常處理好處:
1.出錯不報錯
2.可以進行處理
處理往往是記錄出錯時的一些信息

異常處理案例:
1、

CREATE TABLE test2(
id INT PRIMARY KEY,
NAME VARCHAR(100)
)ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

SELECT * FROM test2;
INSERT INTO test2 VALUES (1,'f');

DROP PROCEDURE IF EXISTS proc_exception1;
DELIMITER //
CREATE PROCEDURE proc_exception1(OUT error VARCHAR(10))
BEGIN 

DECLARE CONTINUE HANDLER FOR SQLWARNING,NOT FOUND,SQLEXCEPTION
     SET error = '23000';   
	
	#變量賦值
	SET error = '00000';

	#執行sql
	INSERT INTO test2 VALUES (1,'f');
	#變量賦值
	SET error = '23001'; 
END //
DELIMITER ;

CALL proc_exception1(@error);
SELECT @error;

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

該語句定義了一個異常處理程序,指定了當某條語句出錯時,採取什麼操作
語義:當某個錯誤( condition_value )發生時,就執行指定的語句(Statement),執行完之後,再決定如何操作( handler_action )
CONTINUE: 繼續執行當前的程序
EXIT: 當前程序終止
該語句必須出現在變量或條件聲明的後面
Statement
可以是單條語句或複合語句
關於SQLSTATE碼
每個MySQL錯誤都有一個唯一的數字錯誤編號( mysql_error_code ),每個錯誤又對應一個5字符的SQLSTATE碼( ANSI SQL 採用)
例16:創建過程,插入一個重複的2號球隊。處理異常,在輸出參數中包含出錯消息的SQLSTATE碼

DELIMITER $$

CREATE  PROCEDURE small_mistake1(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'  
     SET error = '23000';   
   
   SET error = '00000';
   -- 該語句會出錯
   INSERT INTO teams VALUES(2,27,'third');
   
   -- 該語句在異常處理結束後會繼續得到執行
   SET error = '23001';      
 END$$

DELIMITER ;
CALL small_mistake1(@error);
SELECT @error;

在這裏插入圖片描述

DELIMITER $$
CREATE  PROCEDURE small_mistake2(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE EXIT HANDLER FOR SQLSTATE '23000'  
     SET error = '23000';   
 
   SET error = '00000';
   -- 該語句會出錯
   INSERT INTO teams VALUES(2,27,'third');
   
   -- 該語句在異常處理結束後不會得到執行
   SET error = '23001';      
 END$$

DELIMITER ;
CALL small_mistake2(@error);
SELECT @error;

在這裏插入圖片描述
可以在一個過程中定義幾個異常處理程序,針對不同的錯誤進行不同的處理
例17:

DELIMITER $$

CREATE  PROCEDURE small_mistake3(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'  
     SET error = '23000';   
   
   DECLARE CONTINUE HANDLER FOR SQLSTATE '21S01'  
     SET error = '21S01';
     
   -- 該語句會出錯.多了一個參數
   INSERT INTO teams VALUES(2,27,'third',5);    
 END$$

DELIMITER ;
CALL small_mistake3(@error);
SELECT @error;

在這裏插入圖片描述
上例中的異常處理程序也可以使用錯誤編號。例如:

DECLARE CONTINUE HANDLER FOR 1062  
     SET error = '23000';      
   DECLARE CONTINUE HANDLER FOR 1136  
     SET error = '21S01';

以’01’開頭的所有sqlstate碼都對應SQLWARNING處理程序;
以’02’開頭的所有sqlstate碼都對應NOT FOUND 處理程序;
那些不以’01’或’02’開頭的所有sqlstate碼都對應SQLEXCEPTION處理程序。
當我們不想爲每個錯誤都定義一個處理程序時,可以使用這3個處理程序
例18:

DELIMITER $$

CREATE  PROCEDURE small_mistake4(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE CONTINUE HANDLER FOR SQLWARNING,NOT FOUND,SQLEXCEPTION  
     SET error = 'xxxxx';   
          
   -- 該語句會出錯.
   INSERT INTO teams VALUES(2,27,'third');    
 END$$

DELIMITER ;
CALL small_mistake4(@error);
SELECT @error;

在這裏插入圖片描述
給異常編碼起名字

DECLARE condition_name CONDITION FOR condition_value 
其中,condition_value: 
mysql_error_code |
 	SQLSTATE [VALUE]  sqlstate_value

爲了提高可讀性,可以給某個sqlstate代碼或mysql錯誤代碼一個名字,並且在後面的異常處理程序中使用這個名字
例19:

DELIMITER $$

CREATE  PROCEDURE small_mistake5(  
  OUT error VARCHAR(5))   
 BEGIN
   DECLARE non_unique CONDITION FOR SQLSTATE '23000';   
   DECLARE CONTINUE HANDLER FOR non_unique  
     SET error = '23000';   
   -- 該語句會出錯.
   INSERT INTO teams VALUES(2,27,'third');    
 END$$

DELIMITER ;
CALL small_mistake5(@error);
SELECT @error;

在這裏插入圖片描述
案例:

DROP PROCEDURE IF EXISTS proc_exception2;
DELIMITER //
CREATE PROCEDURE proc_exception2(OUT error VARCHAR(10))
BEGIN 

DECLARE non_unique CONDITION FOR 1062;
DECLARE CONTINUE HANDLER FOR non_unique    -- for 1062
     SET error = '23000';   
	
	#變量賦值
	SET error = '00000';
	#執行sql
	INSERT INTO test2 VALUES (1,'f');
	#變量賦值
	SET error = '23001'; 

END //
DELIMITER ;

CALL proc_exception2(@error);
SELECT @error;

注意:
1.可以在捕獲錯誤後不進行操作,即忽略錯誤,如:DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;即將異常處理的SQL語句做成空的。
2.異常捕獲只能定義在begin下面;
3.當異常處理被定義在多個begin end嵌套中間時,報錯時,先去最近的begin end中的異常處理中去捕獲,如果能捕獲到就不會去更外層的begin end 去捕獲了;
4.當有多層begin end的時候,每層都有自己完善的異常處理,自己異常,自己這層去處理。

異常處理嵌套問題
案例:

DELIMITER $$
CREATE  PROCEDURE small_mistake6(
OUT error VARCHAR(5))   
 BEGIN     
   DECLARE non_unique CONTINUE FOR SQLSTATE '23000';
   DECLARE  CONTINUE  HANDLER FOR non_unique
   BEGIN       
     SET error=’23000’;
select error;
   END;
INSERT INTO TEAMS VALUES(2,27,’third’);
 END$$
DELIMITER ;

異常傳播
在嵌套塊的情況下,內部塊中發生異常了,首先由本塊的異常處理程序來處理,如果本塊沒有處理,則由外部塊的異常處理程序來處理
例20:

DELIMITER $$
CREATE  PROCEDURE small_mistake6()   
 BEGIN     
   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'  
     SET @processed = 100;   
   BEGIN       
      DECLARE CONTINUE HANDLER FOR SQLSTATE '21000'  
          SET @processed = 200;     
      -- 該語句會出錯.
      INSERT INTO teams VALUES(2,27,'third');    
   END;
 END$$
DELIMITER ;
CALL small_mistake6();
SELECT @processed;

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章