觸發器是與表事件(INSERT/UPDATE/DELETE)綁定的特殊存儲程序,自動執行,無法手動調用。本文系統講解語法、NEW/OLD 伪表行、時機選擇、多語句封裝、調用存儲過程、錯誤傳播機制,並給出審計日志、數據同步、業務約束等實戰案例。
CREATE TRIGGER `trigger_name`
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON `table_name`
FOR EACH ROW
BEGIN
-- 觸發器體
END;
BEFORE:事件前執行,可修改 NEW 值、阻止操作(拋異常)AFTER:事件後執行,不可修改 NEW,可基於變更做後續動作FOLLOWS/PRECEDES)| 事件 | OLD | NEW | 可修改 NEW |
|---|---|---|---|
| INSERT | 無 | 新行值 | BEFORE 可修改 |
| UPDATE | 舊行值 | 新行值 | BEFORE 可修改 |
| DELETE | 舊行值 | 無 | 不可 |
NEW.col_name、OLD.col_nameSET NEW.col_name = value;(僅 BEFORE INSERT/UPDATE)-- 查看所有
SHOW TRIGGERS;
-- 查看具體
SHOW CREATE TRIGGER `trigger_name`;
-- 刪除
DROP TRIGGER IF EXISTS `trigger_name`;
CREATE TABLE `audit_log` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`table_name` VARCHAR(64) NOT NULL,
`operation` ENUM('INSERT','UPDATE','DELETE') NOT NULL,
`old_data` JSON,
`new_data` JSON,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
DELIMITER $$
CREATE TRIGGER `trg_person_audit_insert`
AFTER INSERT ON `person`
FOR EACH ROW
BEGIN
INSERT INTO `audit_log` (`table_name`, `operation`, `new_data`)
VALUES ('person', 'INSERT', JSON_OBJECT('id', NEW.id, 'username', NEW.username, 'age', NEW.age));
END $$
CREATE TRIGGER `trg_person_audit_update`
AFTER UPDATE ON `person`
FOR EACH ROW
BEGIN
INSERT INTO `audit_log` (`table_name`, `operation`, `old_data`, `new_data`)
VALUES ('person', 'UPDATE',
JSON_OBJECT('id', OLD.id, 'username', OLD.username, 'age', OLD.age),
JSON_OBJECT('id', NEW.id, 'username', NEW.username, 'age', NEW.age));
END $$
CREATE TRIGGER `trg_person_audit_delete`
AFTER DELETE ON `person`
FOR EACH ROW
BEGIN
INSERT INTO `audit_log` (`table_name`, `operation`, `old_data`)
VALUES ('person', 'DELETE', JSON_OBJECT('id', OLD.id, 'username', OLD.username, 'age', OLD.age));
END $$
DELIMITER ;
DELIMITER $$
CREATE TRIGGER `trg_person_age_fix`
BEFORE INSERT ON `person`
FOR EACH ROW
BEGIN
IF NEW.age < 0 THEN SET NEW.age = 0;
ELSEIF NEW.age > 100 THEN SET NEW.age = 100;
END IF;
SET NEW.username = TRIM(NEW.username);
END $$
CREATE TRIGGER `trg_person_age_fix_update`
BEFORE UPDATE ON `person`
FOR EACH ROW
BEGIN
IF NEW.age < 0 THEN SET NEW.age = 0;
ELSEIF NEW.age > 100 THEN SET NEW.age = 100;
END IF;
END $$
DELIMITER ;
DELIMITER $$
CREATE PROCEDURE `sp_validate_age` (INOUT p_age INT)
BEGIN
IF p_age < 0 THEN SET p_age = 0;
ELSEIF p_age > 100 THEN SET p_age = 100;
END IF;
END $$
CREATE TRIGGER `trg_person_age_sp`
BEFORE UPDATE ON `person`
FOR EACH ROW
BEGIN
CALL sp_validate_age(NEW.age);
END $$
DELIMITER ;
-- 捕獲異常示例
DELIMITER $$
CREATE TRIGGER `trg_safe`
BEFORE INSERT ON `t`
FOR EACH ROW
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
INSERT INTO `err_log`(`msg`) VALUES('Trigger error');
-- 可選:RESIGNAL 拋出導致主操作回滾
RESIGNAL;
END;
-- 可能出錯的邏輯
END $$
DELIMITER ;
升級前必須 DROP TRIGGER 所有觸發器,升級後重新創建,否則 DROP TRIGGER 失效。
SET @disable_trigger = 1; 觸發器內判斷跳過)BEFORE 做數據修正/校驗,AFTER 做異步通知/同步trg_{table}_{event}_{timing},如 trg_person_insert_before