MySQL 5.0 引入觸發器支援,滿足 ANSI SQL 標準並回應社群長期需求。觸發器可在資料異動(INSERT/UPDATE/DELETE)前後自動執行定義邏輯,常用於資料驗證、審計日誌、衍生欄位維護等場景。本文系統整理觸發器語法規則、權限模型、NEW/OLD 過渡變數操作、建立與測試範例、CHECK 約束替代方案、已知 Bug 與版本升級注意事項,為開發與 DBA 提供完整參考手冊。
CREATE TRIGGER
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE }
ON
FOR EACH ROW
| 要素 | 關鍵字 | 說明 |
|---|---|---|
| 命名 | 最長 64 字元,建議採用 表名_時機_事件 慣例(如 orders_bu = orders 表 BEFORE UPDATE) | |
| 時機 | BEFORE / AFTER | 事件發生前或後執行;BEFORE 可修改 NEW 值,AFTER 僅能讀取 |
| 事件 | INSERT / UPDATE / DELETE | 觸發的 DML 操作類型 |
| 所屬表 | ON | 觸發器綁定單一表,同一表同一事件同一時機僅能建立一個觸發器 |
| 粒度 | FOR EACH ROW | 逐列觸發(行級觸發),MySQL 僅支援行級,不支援陳述式級 |
| 執行體 | 合法 SQL 陳述式,可含複合陳述式 BEGIN...END、流程控制、變數宣告、例外處理 |
CREATE TRIGGER 權限(MySQL 5.1.6+ 獨立權限;舊版需 SUPER 權限)GRANT CREATE TRIGGER ON db.tbl TO 'dev'@'%';REVOKE CREATE TRIGGER ON db.tbl FROM 'dev'@'%';觸發器主體中引用表欄位必須透過 NEW.col_name 或 OLD.col_name,避免欄位名稱衝突:
| 事件 | 可用變數 | 說明 |
|---|---|---|
| INSERT | NEW | 新列資料;可在 BEFORE 中修改 |
| UPDATE | OLD, NEW | 舊值與新值;BEFORE 可修改 NEW |
| DELETE | OLD | 被刪除的舊列資料 |
CREATE TRIGGER t21_au
BEFORE UPDATE ON t22
FOR EACH ROW
BEGIN
SET @old_val = OLD.s1;
SET @new_val = NEW.s1;
END;//
若 s1 原值 55,執行 UPDATE t21 SET s1 = s1 + 1 後,@old_val=55、@new_val=56。
DELIMITER //
CREATE TABLE t22 (s1 INT)//
CREATE TRIGGER t22_bi
BEFORE INSERT ON t22
FOR EACH ROW
BEGIN
SET @x = 'Trigger was activated!';
SET NEW.s1 = 55; -- 強制覆寫插入值
END;//
DELIMITER ;
INSERT INTO t22 VALUES (1);
SELECT @x, t22.* FROM t22;
-- 結果:
-- @x: 'Trigger was activated!'
-- s1: 55 (非原始插入的 1)
MySQL 不支援標準 SQL CHECK 約束,可用觸發器模擬:
CREATE TABLE t25 (
s1 INT,
s2 CHAR(5),
PRIMARY KEY (s1)
) ENGINE=INNODB//
CREATE TRIGGER t25_bi
BEFORE INSERT ON t25
FOR EACH ROW
BEGIN
IF LEFT(NEW.s2,1) <> 'A' THEN
SET NEW.s1 = 0; -- 觸發主鍵衝突或業務邏輯攔截
END IF;
END;//
CREATE TRIGGER t25_bu
BEFORE UPDATE ON t25
FOR EACH ROW
BEGIN
IF LEFT(NEW.s2,1) <> 'A' THEN
SET NEW.s1 = 0;
END IF;
END;//
關鍵點:
BEFORE 觸發器,因 AFTER 無法修改 NEW觸發器主體不能執行以下操作(同函數限制):
ALTER, CACHE INDEX, CALL, COMMIT, CREATE, DELETE,
DROP, FLUSH PRIVILEGES, GRANT, INSERT, KILL,
LOCK, OPTIMIZE, REPAIR, REPLACE, REVOKE,
ROLLBACK, SAVEPOINT, SELECT FROM table,
SET system variable, SET TRANSACTION,
SHOW, START TRANSACTION, TRUNCATE, UPDATE
例外:SELECT 可用於變數賦值(SELECT ... INTO @var),但不可直接查表返回結果集。
| Bug 編號 | 現象 | 規避方案 |
|---|---|---|
| #5859 | DROP TABLE 不會自動刪除關聯觸發器 | 手動先 DROP TRIGGER 再 DROP TABLE |
| #5892 | 觸發器命名空間錯誤,刪除需加表名前綴 | 使用 DROP TRIGGER tbl_name.trigger_name |
| #5894 | 對有觸發器的表執行 ALTER TABLE 可能導致資料損毀 | 避免在有觸發器的表上執行 ALTER,待修復版本釋出 |
DROP TRIGGER IF EXISTS、INFORMATION_SCHEMA.TRIGGERS 標準查詢SHOW TRIGGERS 匯出定義,注意 DEFINER 權限映射CREATE OR REPLACE TRIGGER 簡化部署腳本觸發器是資料庫層面業務邏輯封裝的利器,善用可集中資料完整性規則、減少應用層重複驗證碼。但需謹記:觸發器隱藏邏輯增加除錯難度、影響寫入效能、複雜觸發器鏈易造成死鎖。建立嚴格的命名規範、文件化所有觸發器用途、在測試環境完整驗證後再部署生產,並隨版本升級及時修復已知缺陷。