觸發器 是與表關聯的命名資料庫物件,當表發生 INSERT/UPDATE/DELETE 事件時自動執行。它是特殊的儲存過程,不由應用呼叫,由資料庫事件驅動。
CREATE TRIGGER `trigger_name`
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON `tbl_name` FOR EACH ROW
BEGIN
-- 觸發器主體:可使用 NEW、OLD 伪列
-- NEW:新行(INSERT/UPDATE)
-- OLD:舊行(UPDATE/DELETE)
END;
BEFORE 可修改 NEW 值(如自動填充、驗證)。AFTER 不可修改 NEW,常用於同步其他表、日誌、統計。CALL 觸發器,不支援顯式事務控制。CREATE TABLE `user` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(50) NOT NULL, `sex` TINYINT DEFAULT 0 ) ENGINE=InnoDB; CREATE TABLE `comment` ( `c_id` INT AUTO_INCREMENT PRIMARY KEY, `u_id` INT NOT NULL, `name` VARCHAR(50) NOT NULL, -- 冗余字段,避免 JOIN `content` VARCHAR(1000) ) ENGINE=InnoDB;
DELIMITER $$
DROP TRIGGER IF EXISTS `trg_user_name_sync`$$
CREATE TRIGGER `trg_user_name_sync`
AFTER UPDATE ON `user` FOR EACH ROW
BEGIN
IF NEW.`name` <> OLD.`name` THEN
UPDATE `comment` SET `name` = NEW.`name` WHERE `u_id` = OLD.`id`;
END IF;
END$$
DELIMITER ;
DELIMITER $$
DROP TRIGGER IF EXISTS `trg_user_delete_cascade`$$
CREATE TRIGGER `trg_user_delete_cascade`
BEFORE DELETE ON `user` FOR EACH ROW
BEGIN
DELETE FROM `comment` WHERE `u_id` = OLD.`id`;
END$$
DELIMITER ;
-- 初始資料
INSERT INTO `user` (`name`) VALUES ('張映'), ('tank');
INSERT INTO `comment` (`u_id`, `name`, `content`) VALUES
(1, '張映', '觸發器測試'), (1, '張映', '解決字段冗余'), (2, 'tank', '使代碼更簡單');
-- 測試改名
UPDATE `user` SET `name` = '蒼鷹' WHERE `id` = 1;
SELECT * FROM `comment` WHERE `u_id` = 1; -- name 應全變為 '蒼鷹'
-- 測試刪除用戶
DELETE FROM `user` WHERE `id` = 1;
SELECT * FROM `comment` WHERE `u_id` = 1; -- 應為空
SHOW TRIGGERS; SHOW CREATE TRIGGER `trg_user_name_sync`; DROP TRIGGER IF EXISTS `trg_user_name_sync`;
| 優點 | 缺點/風險 |
|---|---|
| 自動性:應用層無感知,減少代碼耦合 | 隱蔽性:邏輯在 DB 層,難追蹤、除錯 | 資料完整性:原子性保證,避免「改了主表沒改從表」 | 效能:大量 DML 時觸發器開銷累積,可能成瓶頸 | 集中維護:業務規則集中 DB,多應用共享 | 遷移困難:跨資料庫/異構遷移需重寫 | 審計/日誌:自動記錄變更軌跡 | 鎖爭用:觸發器內操作其他表會延長鎖持有時間 |
trg_{table}_{event}_{purpose},如 trg_order_after_insert_audit。performance_schema.triggers、慢查詢日誌關聯分析。觸發器是資料庫層面的「事件總線」,用得好能簡化應用、保證一致性;用不好會變成隱形效能殺手與維護噩夢。克制使用、文檔先行、效能監控,是駕馭觸發器的鐵律。