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


  最近在做 SQL Server 到 MySQL 的遷移(migration),相較於對表和數據的遷移,最令人犯難的還是在功能性存儲過程腳本的改寫轉換(convert),雖說 MySQL 如今是蓬勃發展,不斷的更新迭代的優化,但是在存儲過程等腳本方面與 Oracle、SQL Server 相比,個人感覺是有所欠缺的,無論是靈活性還是實用性,有時真的是很難達到自己想要的效果,或許這就是為什么存儲過程在 MySQL 中使用較少的原因吧……

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

異常處理語句:

1、DECLARE ... CONDITION …

2、DECLARE ... HANDLER …

3、SIGNAL …

4、RESIGNAL …

5、GET DIAGNOSTICS …

一、常規聲明的異常處理

1、條件聲明

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 語句不能直接運行,只能作為【條件處理】的一部分。

2、條件處理

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 ;

 

二、SIGNAL 與 RESIGNAL

  SIGNAL 與 RESIGNAL 可以通過自定義偽裝系統的錯誤信息以及代碼,刷新當前警告緩沖區域。

1、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 }

 2、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語句,則所有屬性與傳遞給條件處理程序的屬性相同。

3、常見對比使用實例

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 的使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM