USE test;
DROP TABLE IF EXISTS t8;
CREATE TABLE t8(s1 INT, PRIMARY KEY(s1));
DROP PROCEDURE IF EXISTS handlerdemo;
DELIMITER $$
CREATE PROCEDURE handlerdemo()
BEGIN
DECLARE xx INT DEFAULT 4;
-- 定義條件:SQLSTATE 23000 = 完整性約束違反
DECLARE oh_no CONDITION FOR SQLSTATE '23000';
-- 退出型處理器:遇到條件設置變量並退出 BEGIN...END
DECLARE EXIT HANDLER FOR oh_no SET @info = '違反主鍵約束';
SET @X = 1;
INSERT INTO t8 VALUES(1); -- 成功
SET @X = 2;
INSERT INTO t8 VALUES(1); -- 觸發主鍵衝突,跳轉到 EXIT HANDLER
SET @X = 3; -- 不會執行
END $$
DELIMITER ;
-- 調用與驗證
CALL handlerdemo();
SELECT @X, @info;
-- 結果:@X=2, @info='違反主鍵約束'
; 需被屏蔽,故重定義分隔符DELIMITER //,結束後 DELIMITER ; 恢復,後續可繼續寫別的語句DELIMITER $$,結束用 $$,但之後不能再寫其他語句,否則解析錯誤| 類型 | 語法 | 作用域 | 聲明要求 |
|---|---|---|---|
| 局部變量 | DECLARE var INT; | 僅存儲過程內部 | 必須聲明,置於 BEGIN 後首部 |
| 用戶變量 | @var | 會話級(跨存儲過程可見) | 無需聲明,直接賦值 |
| 系統變量 | @@session.var | 會話/全局 | 只讀或特權修改 |
困惑點: 為何局部變量強制聲明位置,而用戶變量隨意用?這是 MySQL 歷史演進留下的不一致性。
-- 1. 定義條件別名 DECLARE oh_no CONDITION FOR SQLSTATE '23000'; -- 或直接用錯誤碼 DECLARE dup_key CONDITION FOR 1062; -- 2. 綁定處理器 DECLARE EXIT HANDLER FOR oh_no SET @msg = '錯誤'; DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @retry = 1;
EXIT HANDLER:執行處理邏輯後退出當前 BEGIN...END 塊CONTINUE HANDLER:執行處理邏輯後繼續執行後續語句SQLSTATE、MySQL 錯誤碼、SQLEXCEPTION、SQLWARNING、NOT FOUNDCONTINUE HANDLER 捕獲死鎖,SLEEP() 後重試EXIT HANDLER 寫入審計表再拋出ROLLBACK 確保一致性