在 MySQL 觸發器中,若要根據業務邏輯攔截資料寫入(如禁止特定值入庫),官方並未提供直接的 RETURN 或 THROW 機制。常見的變通做法是「故意製造一條會報錯的 SQL」,利用錯誤中斷觸發器繼續執行,進而回滾外層的 DML 語句。
在 BEFORE INSERT 或 BEFORE UPDATE 觸發器中,判斷條件不滿足時,執行一條注定失敗的語句(如向擁有主鍵的表插入重複鍵、或操作一個不存在的表)。MySQL 會拋出錯誤,導致觸發器終止,外層的 INSERT/UPDATE 也隨之回滾。
CREATE TABLE t_control (id INT PRIMARY KEY);
INSERT INTO t_control VALUES (1); -- 預先插入一行
DELIMITER //
CREATE TRIGGER tr_t_bluerosehero_bi
BEFORE INSERT ON t_bluerosehero
FOR EACH ROW
BEGIN
IF NEW.col > 30 THEN
INSERT INTO t_control VALUES (1); -- 重複主鍵 → ERROR 1062
END IF;
END//
DELIMITER ;
測試:
INSERT INTO t_bluerosehero VALUES (1, 20); -- 成功
INSERT INTO t_bluerosehero VALUES (2, 40); -- ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
結果:只有 col=20 的行被寫入,col=40 被攔截。
DELIMITER //
CREATE TRIGGER tr_t_bluerosehero_bi2
BEFORE INSERT ON t_bluerosehero
FOR EACH ROW
BEGIN
DECLARE i INT;
IF NEW.col > 30 THEN
INSERT INTO xxxx VALUES (1); -- 表不存在 → ERROR 1146 (42S02)
END IF;
END//
DELIMITER ;
效果相同,錯誤碼不同,可根據監控系統偏好選擇。
BEFORE 觸發器;AFTER 觸發器中拋錯無法回滾已提交的 DML。SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '...',語義更清晰、不依賴副作用。若版本允許,優先使用 SIGNAL;老版本或需快速驗證時,上述「製造錯誤法」是可靠的臨時方案。生產環境建議配合應用層驗證雙重把關,避免過度依賴資料庫端攔截。