變量定義與賦值三板斧
1. DECLARE 區域變量(僅限 BEGIN...END 塊開頭)
DECLARE var_name[,...] type [DEFAULT value];
-- 變量名不能帶 @,易與用戶變量/參數混淆
DECLARE pname VARCHAR(20) DEFAULT '陳';
DECLARE cnt INT DEFAULT 0;
2. SET 賦值(可同時聲明用戶變量)
-- 給已聲明變量賦值
SET pname = '王';
-- 邊聲明邊賦值(用戶變量,帶 @,作用域全會話)
SET @id = 1;
3. SELECT ... INTO 賦值(查詢結果直接入變量/參數)
-- 入區域變量
SELECT COUNT(*) INTO cnt FROM employee WHERE depid = pdepid;
-- 直接入 OUT 參數
SELECT COUNT(*) INTO pcount FROM employee WHERE depid = pdepid;
條件處理機制:讓存儲過程具備異常捕獲能力
步驟一:聲明條件名稱(可選,提高可讀性)
DECLARE reprimary CONDITION FOR 1062; -- 錯誤碼
DECLARE dup_key CONDITION FOR SQLSTATE '23000'; -- SQLSTATE
步驟二:聲明 Handler(核心)
DECLARE handler_type HANDLER FOR condition_value[,...] statement;
handler_type:
CONTINUE -- 執行 statement 後繼續後續邏輯
EXIT -- 執行 statement 後退出當前 BEGIN...END 塊
UNDO -- 保留未實現
condition_value:
SQLSTATE 'xxxxx'
condition_name
SQLWARNING -- 01 開頭 SQLSTATE 速記
NOT FOUND -- 02 開頭 SQLSTATE 速記(游標耗盡)
SQLEXCEPTION -- 其他所有錯誤
mysql_error_code
實戰演示:主鍵衝突的三種處理姿勢
場景:批量插入,主鍵可能重複
CREATE TABLE Employee (
id INT PRIMARY KEY, name VARCHAR(20), depid INT
);
INSERT INTO Employee VALUES (1,'陳',100);
姿勢 1:無 Handler → 直接報錯終止
CALL Pro_Insert_No_Handler();
-- ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
-- 後續語句不執行
姿勢 2:EXIT Handler → 記錄錯誤並退出
CREATE PROCEDURE Pro_Insert_Exit()
BEGIN
DECLARE reprimary CONDITION FOR 1062;
DECLARE EXIT HANDLER FOR reprimary SET @x = 1;
SET @id = 1; INSERT INTO Employee VALUES (1,'陳',100); -- 衝突
SET @id = 2; INSERT INTO Employee VALUES (6,'陳',100); -- 不執行
SET @id = 3;
END;
CALL Pro_Insert_Exit();
SELECT @id, @x; -- @id=1, @x=1
姿勢 3:CONTINUE Handler → 記錄錯誤並繼續
CREATE PROCEDURE Pro_Insert_Continue()
BEGIN
DECLARE reprimary CONDITION FOR SQLSTATE '23000';
DECLARE CONTINUE HANDLER FOR reprimary SET @x = 1;
SET @id = 1; INSERT INTO Employee VALUES (1,'陳',100); -- 衝突
SET @id = 2; INSERT INTO Employee VALUES (6,'陳',100); -- 執行
SET @id = 3;
END;
CALL Pro_Insert_Continue();
SELECT @id, @x; -- @id=3, @x=1
進階:結合事務實現「遇錯全盤回滾」
CREATE PROCEDURE Pro_Insert_Tx()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @err = 1;
START TRANSACTION;
SET @id = 1; INSERT INTO Employee VALUES (7,'陳',100); -- 成功
SET @id = 2; INSERT INTO Employee VALUES (6,'陳',100); -- 主鍵衝突
SET @id = 3;
IF @err = 1 THEN
ROLLBACK; -- id=7 也被回滾
ELSE
COMMIT;
END IF;
END;
性能優化建議
- 減少驗證頻率: 用事務包裹批量操作,僅在提交前檢查錯誤標誌
- 優化 Handler 範圍: 盡量用具體錯誤碼/SQLSTATE 替代
SQLEXCEPTION
- 游標循環中: 遇錯立即
LEAVE 循環,避免無效迭代
避坑指南
- DECLARE 必須在 BEGIN...END 開頭,且在所有語句之前
2. 區域變量無 @,用戶變量有 @,參數無 @ 但有 IN/OUT/INOUT
3. NOT FOUND 主要用於游標 FETCH 耗盡,非查詢無結果
4. UNDO HANDLER 尚未實現,勿使用
5. Handler 執行的 statement 只能是單條 SQL,塊語法需包在 BEGIN...END