MySQL 儲存程序是封裝業務邏輯、提升效能、保障資料一致性的利器。本文提供一個生產級範例 pro_rep_shadow_rs,完整展示輸出參數、事務控制、異常處理、巢狀呼叫、游標迴圈、條件判斷等核心特性,適合作為開發參考範本。
DROP PROCEDURE IF EXISTS pro_rep_shadow_rs;
DELIMITER |
CREATE PROCEDURE pro_rep_shadow_rs(OUT rtn INT)
BEGIN
-- 變數宣告(必須在非宣告語句之前)
DECLARE iLast_rep_sync_id INT DEFAULT -1;
DECLARE iMax_rep_sync_id INT DEFAULT -1;
-- 異常處理:遇到 SQL 例外直接回滾,不再拋給呼叫端
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
-- 1. 取得上次同步進度
SELECT eid INTO iLast_rep_sync_id
FROM rep_de_proc_log
WHERE tbl = 'rep_shadow_rs';
-- 2. 首次執行初始化
IF iLast_rep_sync_id = -1 THEN
INSERT INTO rep_de_proc_log(rid, eid, tbl) VALUES (0, 0, 'rep_shadow_rs');
SET iLast_rep_sync_id = 0;
END IF;
-- 3. 計算本次處理起始 ID
SET iLast_rep_sync_id = iLast_rep_sync_id + 1;
SET rtn = 0; -- 預設失敗
-- 4. 開啟事務
START TRANSACTION;
-- 5. 取得來源表最大同步 ID
SELECT MAX(rep_sync_id) INTO iMax_rep_sync_id
FROM rep_shadow_rs;
-- 6. 有新資料才處理
IF iMax_rep_sync_id >= iLast_rep_sync_id THEN
CALL pro_rep_shadow_rs_do(iLast_rep_sync_id, iMax_rep_sync_id);
UPDATE rep_de_proc_log
SET rid = iLast_rep_sync_id, eid = iMax_rep_sync_id
WHERE tbl = 'rep_shadow_rs';
END IF;
-- 7. 提交事務並標記成功
COMMIT;
SET rtn = 1;
END;
|
DELIMITER ;
rid(起始) 與 eid(結束) ID,實現增量同步。pro_rep_shadow_rs_do,職責分離清晰。DROP PROCEDURE IF EXISTS pro_rep_shadow_rs_do;
DELIMITER |
CREATE PROCEDURE pro_rep_shadow_rs_do(
IN last_rep_sync_id INT,
IN max_rep_sync_id INT
)
BEGIN
DECLARE iRep_Operationtype CHAR(1);
DECLARE iRep_status CHAR(1);
DECLARE iRep_Sync_id INT;
DECLARE iId INT;
DECLARE stop_flag INT DEFAULT 0;
-- 游標:抓取指定 ID 區間的待同步資料
DECLARE cur CURSOR FOR
SELECT id, Rep_Operationtype, Rep_status, rep_sync_id
FROM rep_shadow_rs
WHERE rep_sync_id BETWEEN last_rep_sync_id AND max_rep_sync_id;
-- 游標結束處理器
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET stop_flag = 1;
OPEN cur;
FETCH cur INTO iId, iRep_Operationtype, iRep_status, iRep_Sync_id;
WHILE stop_flag <> 1 DO
-- 根據操作類型與狀態決定動作
IF iRep_Operationtype = 'I' THEN
INSERT INTO rs0811 (id, fnbm)
SELECT id, fnbm FROM rep_shadow_rs WHERE rep_sync_id = iRep_Sync_id;
ELSEIF iRep_Operationtype = 'U' THEN
IF iRep_status = 'A' THEN
INSERT INTO rs0811 (id, fnbm)
SELECT id, fnbm FROM rep_shadow_rs WHERE rep_sync_id = iRep_Sync_id;
ELSEIF iRep_status = 'B' THEN
DELETE FROM rs0811 WHERE id = iId;
END IF;
ELSEIF iRep_Operationtype = 'D' THEN
DELETE FROM rs0811 WHERE id = iId;
END IF;
FETCH cur INTO iId, iRep_Operationtype, iRep_status, iRep_Sync_id;
END WHILE;
CLOSE cur;
END;
|
DELIMITER ;
CALL pro_rep_shadow_rs(@rtn);
SELECT @rtn; -- 1 成功,0 失敗
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; 保留錯誤資訊供監控告警。本範例涵蓋 MySQL 儲存程序 90% 常用進階特性,結構清晰、邏輯完整,可直接作為增量同步、資料遷移、ETL 等場景的開發藍本。掌握其設計模式,能顯著提升資料庫端業務封裝能力。