CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON table_name
FOR EACH ROW
trigger_body
| 子句 | 說明 |
|---|---|
trigger_name | 唯一標識,建議格式:t_{before|after}_{insert|update|delete}_on_{table} |
BEFORE / AFTER | 觸發時機:語句執行前/後。BEFORE 可修改 NEW 值、攔截操作;AFTER 不可修改 NEW,用於日誌/同步/統計。 |
INSERT / UPDATE / DELETE | 觸發事件。同一表同一事件同一時機**只能建一個觸發器** (5.7+ 支持多個,但須指定 FOLLOWS/PRECEDES)。 |
FOR EACH ROW | 行級觸發 (MySQL 僅支援行級)。每影響一行執行一次。 |
trigger_body | 執行體。單句無需 BEGIN/END;多句必須包裹。 |
| 事件 | NEW | OLD | 可修改 NEW |
|---|---|---|---|
| INSERT | 新行值 (可修改,BEFORE 中) | 不可用 (NULL) | ✅ BEFORE |
| UPDATE | 新值 (可修改,BEFORE 中) | 舊值 (只讀) | ✅ BEFORE |
| DELETE | 不可用 | 被刪行值 (只讀) | ❌ |
引用方式:NEW.col_name, OLD.col_name。
-- 建表
CREATE TABLE tab1 (id VARCHAR(11) PRIMARY KEY);
CREATE TABLE tab2 (id VARCHAR(11) PRIMARY KEY);
-- AFTER INSERT: 同步新增
CREATE TRIGGER t_after_insert_on_tab1
AFTER INSERT ON tab1
FOR EACH ROW
BEGIN
INSERT INTO tab2 (id) VALUES (NEW.id);
END;
-- AFTER DELETE: 同步刪除
CREATE TRIGGER t_after_delete_on_tab1
AFTER DELETE ON tab1
FOR EACH ROW
BEGIN
DELETE FROM tab2 WHERE id = OLD.id;
END;
-- 測試
INSERT INTO tab1 VALUES ('0001');
SELECT * FROM tab1; -- 0001
SELECT * FROM tab2; -- 0001
DELETE FROM tab1 WHERE id = '0001';
SELECT * FROM tab1; -- 空
SELECT * FROM tab2; -- 空
CREATE TRIGGER t_before_insert_on_user
BEFORE INSERT ON `user`
FOR EACH ROW
BEGIN
-- 1. 手機號格式校驗
IF NEW.phone NOT REGEXP '^1[3-9][0-9]{9}$' THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '手機號格式錯誤';
END IF;
-- 2. 自動生成創建時間
IF NEW.created_at IS NULL THEN
SET NEW.created_at = NOW();
END IF;
-- 3. 敏感字過濾 (示例)
SET NEW.nickname = REPLACE(NEW.nickname, '敏感詞', '***');
END;
關鍵點:SIGNAL SQLSTATE '45000' 主動拋出異常,**導致觸發器所在語句回滾** (INSERT/UPDATE 不執行)。
-- 建立 BEFORE UPDATE 觸發器,故意報錯
CREATE TRIGGER t_bu_planinfo
BEFORE UPDATE ON planinfo
FOR EACH ROW
BEGIN
INSERT INTO not_exist_table VALUES (NEW.planid); -- 表不存在,報錯
END;
-- 執行 UPDATE
UPDATE planinfo SET showprob = 200 WHERE planid = 1;
-- ERROR 1146 (42S02): Table 'not_exist_table' doesn't exist
-- 檢查數據
SELECT showprob FROM planinfo WHERE planid = 1; -- 仍為舊值,UPDATE 已回滾
結論:BEFORE 觸發器是**守門員**,任何錯誤直接攔截主操作,保證原子性。
TRIGGER 權限 (5.1.6+ 獨立權限,早期需 SUPER)。SHOW TRIGGERS; / SELECT * FROM information_schema.TRIGGERS;。DROP TRIGGER [IF EXISTS] [schema.]trigger_name;。.TRG 文件 (表級) 和 information_schema。SET @in_trigger = 1; 判斷跳出。LOAD DATA、DELETE FROM table (無 WHERE) 會逐行觸發,**極慢**。大批量操作前 DROP TRIGGER,事後重建。mysqldump --triggers (默認開啟)。log_bin_trust_function_creators=1 等配置,或主庫不建觸發器、從庫單獨建。