觸發器基礎語法
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON tbl_name FOR EACH ROW
trigger_body
核心限制
- 單表單事件唯一:一張表上同一事件(如 AFTER INSERT)只能建一個觸發器
- 需變更結束符:
DELIMITER // ... DELIMITER ;
- 存取變更行:
NEW.col(新值)、OLD.col(舊值)
- 執行順序:BEFORE → 行操作 → AFTER,任一失敗整體回滾(事務表)
基礎範例:跨表同步
DROP TRIGGER IF EXISTS tr_testTri;
DELIMITER //
CREATE TRIGGER tr_testTri
AFTER INSERT ON testTri
FOR EACH ROW
BEGIN
INSERT INTO test (Col1, Col2, Col3, Col4) VALUES (1, 2, 3, 5);
END//
DELIMITER ;
-- 驗證
INSERT INTO testTri (Col1, Col2, Col3, Col4) VALUES (1, 2, 3, 4);
-- test 表自動新增一行
遞歸與循環觸發實測(均被阻擋)
場景一:自我遞歸
DROP TRIGGER IF EXISTS tr_testTri;
DELIMITER //
CREATE TRIGGER tr_testTri
AFTER INSERT ON testTri
FOR EACH ROW
BEGIN
INSERT INTO testTri (Col1, Col2, Col3, Col4) VALUES (1, 2, 3, 5);
END//
DELIMITER ;
-- 測試
INSERT INTO testTri (Col1, Col2, Col3, Col4) VALUES (1, 2, 3, 4);
-- Error 1442: Can't update table 'testtri' in stored function/trigger
-- because it is already used by statement which invoked this stored function/trigger.
場景二:雙表相互觸發
-- testTri 觸發器寫 test
CREATE TRIGGER tr_testTri AFTER INSERT ON testTri ...
INSERT INTO test ...;
-- test 觸發器寫 testTri
CREATE TRIGGER tr_test AFTER INSERT ON test ...
INSERT INTO testTri ...;
-- 測試
INSERT INTO testTri ...;
-- Error 1442: 同樣報錯,循環引用被檢測並阻擋
觸發器效能與最佳實踐
| 建議 | 理由 |
| 謹慎使用,核心業務避免 | 隱式邏輯、難調試、效能損耗 |
| 避免複雜邏輯/外部呼叫 | 阻塞主操作、擴大事務範圍 |
| 統計/審計/同步等非核心場景 | 可接受最終一致性、邊緣業務 |
| Row 格式主從:從庫不執行觸發器 | 需主庫寫 binlog,從庫重放 SQL |
| 防止遞歸:業務層控制或標記欄位 | 資料庫層無法可靠防禦 |
版本差異提示
- MySQL 5.7+:支援同一表同一事件**多個觸發器**(
FOLLOWS/PRECEDES 控制順序)
- 本文測試基於 5.6,單觸發器限制在 8.0 已放寬
總結
- 觸發器威力大但雙刃劍,**業務核心鏈路禁用**
- 資料庫層**原生阻擋遞歸與循環觸發**(Error 1442)
- 適用:審計日誌、冗余表同步、非關鍵統計
- 調試難:無斷點、錯誤堆棧不明確、事務邊界模糊
- 上一篇文章: MySQL UPDATE 子查詢報錯 1093 解決方案:改用 JOIN 多表更新模式
- 下一篇文章: SQL Server 2008 聚合查詢與分組分析完全指南
Copyright ©
程式碼之家 All Rights Reserved