MySQL-[SIGNAL/RESIGNAL/GET DIAGNOSTICS]的使用

  最近在作 SQL Server 到 MySQL 的遷移(migration),相較於對錶和數據的遷移,最使人犯難的仍是在功能性存儲過程腳本的改寫轉換(convert),雖然說 MySQL 現在是蓬勃發展,不斷的更新迭代的優化,可是在存儲過程等腳本方面與 Oracle、SQL Server 相比,我的感受是有所欠缺的,不管是靈活性仍是實用性,有時真的是很難達到本身想要的效果,或許這就是爲何存儲過程在 MySQL 中使用較少的緣由吧……html

  承接上一篇關於MySQL的異常處理,繼續異常處理的擴展性用法:mysql

異常處理語句:sql

一、DECLARE ... CONDITION …app

二、DECLARE ... HANDLER …
優化

三、SIGNAL …
spa

四、RESIGNAL …
code

五、GET DIAGNOSTICS …
orm

1、常規聲明的異常處理htm

一、條件聲明blog

DECLARE condition_name CONDITION FOR condition_value condition_value: { mysql_error_code | SQLSTATE [VALUE] sqlstate_value }

  condition_name:標準的變量命名;

  condition_value:SQLSTATE 值或者 MySQL 自身的 ERROR CODE ;

注:單獨的 condition 語句不能直接運行,只能做爲【條件處理】的一部分。

二、條件處理

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

  handler_action:表明處理的動做,經常使用的是繼續(CONTIUE)和直接退出(EXIT);

  condition_value:異常處理捕獲條件或狀況,包括【條件聲明】裏的 SQLSTATE, MYSQL EEROR CODE, condition_name 以及範圍混淆的其餘兩種;

注:SQLWARNING、SQLEXCEPTION、NOT FOUND 表示任何不存在的 WARNING 或者 ERROR。

mysql> DESC tab7; 
ERROR 1146 (42S02): Table 'TestDB.tab7' doesn't exist


DELIMITER // CREATE PROCEDURE PROC_1() BEGIN DECLARE CONTINUE HANDLER FOR 1146 BEGIN -- body of handler END; DECLARE not_exist_table CONDITION FOR 1146; DECLARE CONTINUE HANDLER FOR not_exist_table BEGIN -- body of handler END; DECLARE not_exist_table CONDITION FOR SQLSTATE '42S02'; DECLARE CONTINUE HANDLER FOR not_exist_table BEGIN -- body of handler END; END // DELIMITER ;

 

2、SIGNAL 與 RESIGNAL

  SIGNAL 與 RESIGNAL 能夠經過自定義假裝系統的錯誤信息以及代碼,刷新當前警告緩衝區域。

一、SIGNAL

  SIGNAL是「返回」錯誤的方法,向處理程序,應用程序的外部部分或客戶端提供錯誤信息。

  此外,它還能夠控制錯誤的特徵(錯誤號,SQLSTATE值,消息)。 若是沒有SIGNAL,則必須採用諸如故意引用不存在的表之類的解決方法來致使例程返回錯誤。

SIGNAL condition_value [SET signal_information_item [, signal_information_item] ...] condition_value: { SQLSTATE [VALUE] sqlstate_value | condition_name } signal_information_item: condition_information_item_name = simple_value_specification condition_information_item_name: { CLASS_ORIGIN | SUBCLASS_ORIGIN | MESSAGE_TEXT | MYSQL_ERRNO | CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | CATALOG_NAME | SCHEMA_NAME | TABLE_NAME | COLUMN_NAME | CURSOR_NAME }

 二、RESIGNAL

  一樣的,RESIGNAL 也能夠異常處理並返回錯誤信息。

RESIGNAL [condition_value]
    [SET signal_information_item [, signal_information_item] ...] condition_value: { SQLSTATE [VALUE] sqlstate_value | condition_name } signal_information_item: condition_information_item_name = simple_value_specification condition_information_item_name: { CLASS_ORIGIN | SUBCLASS_ORIGIN | MESSAGE_TEXT | MYSQL_ERRNO | CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | CATALOG_NAME | SCHEMA_NAME | TABLE_NAME | COLUMN_NAME | CURSOR_NAME }

  經過對比 SIGNAL 與 RESIGNAL 的語法,在使用 SIGNAL 方法的時候必須指定 condition_value ,也就是說其不能單獨使用,須要先定義異常處理,能夠在存儲過程當中的任何位置使用 SIGNAL 語句。

  而 RESIGNAL 能夠省略RESIGNAL語句的全部屬性,甚至能夠省略SQLSTATE值,但必須在錯誤或警告處理程序中使用 RESIGNAL 語句,不然將收到一條錯誤消息,指出「RESIGNAL when handler is not active」。若是單獨使用RESIGNAL語句,則全部屬性與傳遞給條件處理程序的屬性相同。

三、常見對比使用實例

DELIMITER //
CREATE PROCEDURE `test_proc`(var1 int,var2 int)
BEGIN
    declare ErrorMessage           varchar(255) ;
    -- SIGNAL Declarations    
    declare EXP_CONDITION condition for sqlstate 'EX000' ;
    declare exit handler for sqlstate 'EX000' begin
        signal EXP_CONDITION set message_text = ErrorMessage ;
    end ;
    -- RESIGNAL Declarations
    declare exit handler for sqlstate '42S02' begin
        resignal set message_text = 'Unknown tables appear in the process body.' ;
    end ;
    -- Processing
    if( var1 <> var2 ) then
        set ErrorMessage = 'The first number input does not equal the second number.' ;
        signal EXP_CONDITION set message_text = ErrorMessage ;
    end if ;
    select * from xxx ;        -- unknow table xxx
END //
DELIMITER ;

mysql> call test_proc(1,1); ERROR 1146 (42S02): Unknown tables appear in the process body. mysql> call test_proc(1,2); ERROR 1644 (EX000): The first number input does not equal the second number.

  推薦使用 SIGNAL,靈活隨機,在定義好後便可將 SIGNAL 語句放到任何你想放的地方進行判斷預警處理。

 

、GET DIAGNOSTICS

  5.6開始支持的語法,從而獲取錯誤緩衝區的內容,而後把這些內容輸出到不一樣範圍域的變量裏,以便後續靈活操做處理。

GET [CURRENT | STACKED] DIAGNOSTICS { statement_information_item [, statement_information_item] ... | CONDITION condition_number condition_information_item [, condition_information_item] ... } statement_information_item: target = statement_information_item_name condition_information_item: target = condition_information_item_name statement_information_item_name: NUMBER
  | ROW_COUNT condition_information_item_name: { CLASS_ORIGIN | SUBCLASS_ORIGIN | RETURNED_SQLSTATE | MESSAGE_TEXT | MYSQL_ERRNO | CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | CATALOG_NAME | SCHEMA_NAME | TABLE_NAME | COLUMN_NAME | CURSOR_NAME }

  statement_information_item:statment 執行狀況信息捕獲反饋,包括 NUMBER、ROW_COUNT;

  condition_information_item:捕獲異常狀況信息;

  當條件發生,能夠經過變量去接收條件項目信息,但也不是說有的 MySQL 都會進行填充賦值,也會出現空值的(例如:SCHEMA_NAME and TABLE_NAME is null when drop table)。

mysql> delete from t5; Query OK, 3 rows affected (0.04 sec) mysql> GET DIAGNOSTICS @p3 = NUMBER, @p4 = ROW_COUNT; Query OK, 0 rows affected (0.00 sec) mysql> select @p3,@p4; +------+------+
| @p3  | @p4  |
+------+------+
|    0 |    3 |
+------+------+
1 row in set (0.00 sec) mysql> drop table xxx; ERROR 1051 (42S02): Unknown table 'TestDB.xxx' mysql> show warnings;    -- or show error
+-------+------+----------------------------+
| Level | Code | Message                    |
+-------+------+----------------------------+
| Error | 1051 | Unknown table 'TestDB.xxx' |
+-------+------+----------------------------+
1 row in set (0.00 sec) mysql> GET DIAGNOSTICS CONDITION 1
    -> @p1 = RETURNED_SQLSTATE, @p2 = MESSAGE_TEXT; Query OK, 0 rows affected (0.00 sec) mysql> select @p1,@p2; +-------+----------------------------+
| @p1   | @p2                        |
+-------+----------------------------+
| 42S02 | Unknown table 'TestDB.xxx' |
+-------+----------------------------+
1 row in set (0.00 sec)

注:我的認爲,由於使用 GET DIAGNOSTICS 略有些雞肋,使用選擇上更多的會是用 SIGNAL 語句進行異常處理,因此在此不作深究 GET DIAGNOSTICS 的使用。

相關文章
相關標籤/搜索