與表綁定的**被動執行**程序:表發生 INSERT/UPDATE/DELETE 時,自動觸發預定義 SQL。**觸發動作與觸發器體在同一事務中**(原子性:全成或全滾)。
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON table_name
FOR EACH ROW
BEGIN
-- trigger body
END;
BEFORE:約束/修正數據(可修改 NEW)、阻止操作(SIGNAL)AFTER:日誌記錄、衍生表同步、異步通知(不可修改 NEW)FOR EACH ROW:行級觸發(MySQL 僅支持行級)NEW:INSERT/UPDATE 可用,指向新行OLD:UPDATE/DELETE 可用,指向舊行CREATE TABLE `user` (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
account VARCHAR(255), name VARCHAR(255), address VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `user_history` (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
operate_type VARCHAR(50) NOT NULL,
operate_time DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
DELIMITER ;;
-- INSERT 觸發
CREATE TRIGGER tri_insert_user AFTER INSERT ON `user`
FOR EACH ROW
BEGIN
INSERT INTO user_history(user_id, operate_type, operate_time)
VALUES (NEW.id, 'INSERT', NOW());
END;;
-- UPDATE 觸發
CREATE TRIGGER tri_update_user AFTER UPDATE ON `user`
FOR EACH ROW
BEGIN
INSERT INTO user_history(user_id, operate_type, operate_time)
VALUES (NEW.id, 'UPDATE', NOW());
END;;
-- DELETE 觸發
CREATE TRIGGER tri_delete_user AFTER DELETE ON `user`
FOR EACH ROW
BEGIN
INSERT INTO user_history(user_id, operate_type, operate_time)
VALUES (OLD.id, 'DELETE', NOW());
END;;
DELIMITER ;
INSERT INTO user(account,name,address) VALUES('u1','u1','u1');
INSERT INTO user(account,name,address) VALUES('u2','u2','u2');
UPDATE user SET name='u3',account='u3',address='u3' WHERE name='u1';
DELETE FROM user WHERE name='u2';
SELECT * FROM user_history;
-- 4 行記錄:2 INSERT, 1 UPDATE, 1 DELETE
CREATE TRIGGER tri_user_before_ins BEFORE INSERT ON `user`
FOR EACH ROW
BEGIN
IF NEW.account IS NULL OR NEW.account = '' THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'account 不能為空';
END IF;
SET NEW.account = TRIM(LOWER(NEW.account)); -- 統一格式
END;
CREATE TRIGGER tri_user_audit AFTER UPDATE ON `user`
FOR EACH ROW
BEGIN
IF OLD.name <> NEW.name THEN
INSERT INTO audit_log(table_name, pk_id, field, old_val, new_val)
VALUES ('user', NEW.id, 'name', OLD.name, NEW.name);
END IF;
-- 同理比對其他字段
END;
| 坑點 | 後果 | 規避 |
|---|---|---|
| 觸發器中調用存儲過程/函數執行慢 SQL | 主表寫入延遲飆升、鎖持有久 | 觸發器體**極簡**、異步任務拋入消息隊列 |
| 遞歸觸發(觸發器修改同表再觸發) | 無限循環、棧溢出 | 嚴禁在觸發器中操作同表,或用會話變量標記防重入 |
| 大量觸發器導致維護困難 | 業務邏輯分散在應用+觸發器,難追蹤 | **核心業務邏輯留應用層**,觸發器僅用於審計、同步、約束 |
| 備份/遷移遺漏觸發器 | 邏輯丟失 | mysqldump --triggers(默認開啟),版本控制存儲觸發器 DDL |
SHOW TRIGGERS;
SELECT * FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA='db_name';
DROP TRIGGER trigger_name;
觸發器是「數據庫的 AOP」:**橫切關注點**(審計、同步、約束)下沉利器。**克制使用、保持簡單、嚴禁遞歸、邏輯上移應用層**,才能發揮優勢而不成累贅。