{"msg":"操作成功","code":200,"data":{"createBy":"admin","createTime":"2025-03-18 19:06:05","updateBy":"admin","updateTime":"2025-03-18 19:06:05","remark":null,"id":104,"articleTitle":"MySQL（十三）触发器TRIGGER","articleUrl":"mysql_trigger","articleThumbnail":"https://www.asumimoe.com/imgfiles/20220908/9e192744fab244d39d3b15fca035c9f7.jpg","articleFlag":"0","draftStatus":"1","reprintStatement":"0","articleSummary":"触发器是一种与表关联的预定义数据库操作，在满足特定数据变更事件（`INSERT`/`UPDATE`/`DELETE`）时**自动执行**，无需人工调用。","articleContent":"触发器是一种与表关联的 **预定义数据库操作**，在满足特定数据变更事件（`INSERT`/`UPDATE`/`DELETE`）时**自动执行**，无需人工调用。\n\n**核心特性**：\n\n| 特性             | 说明                                                 |\n| ---------------- | ---------------------------------------------------- |\n| **事件驱动**     | 响应表上的 `INSERT`、`UPDATE`、`DELETE` 操作         |\n| **自动执行**     | 满足条件时由数据库引擎自动触发                       |\n| **无显式调用**   | 应用程序无需编写触发逻辑                             |\n| **事务绑定**     | 与触发语句在同一事务中执行（成功则提交，失败则回滚） |\n| **访问新旧数据** | 通过 `OLD` 和 `NEW` 伪记录访问修改前后的数据         |\n\n\n\n## 触发器类型与执行时机\n\n| 类型            | 触发时机           | 典型场景                       |\n| --------------- | ------------------ | ------------------------------ |\n| `BEFORE INSERT` | 数据插入**前**执行 | 数据校验、自动填充字段         |\n| `AFTER INSERT`  | 数据插入**后**执行 | 更新统计表、发送通知           |\n| `BEFORE UPDATE` | 数据更新**前**执行 | 防止非法修改、记录修改历史     |\n| `AFTER UPDATE`  | 数据更新**后**执行 | 同步冗余数据、触发下游业务     |\n| `BEFORE DELETE` | 数据删除**前**执行 | 阻止重要数据删除、级联删除检查 |\n| `AFTER DELETE`  | 数据删除**后**执行 | 归档删除记录、更新计数器       |\n\n## 创建触发器语法详解\n\n```sql\nDELIMITER $$\n\nCREATE TRIGGER trigger_name\n[BEFORE | AFTER] [INSERT | UPDATE | DELETE] \nON table_name FOR EACH ROW\n[trigger_order] -- MySQL 8.0+ 支持执行顺序控制\nBEGIN\n    -- 触发器逻辑\n    -- 可访问 OLD 和 NEW 伪记录\n    -- 支持SQL语句、流程控制、变量操作\nEND$$\n\nDELIMITER ;\n```\n\n**关键元素**：\n\n- **`FOR EACH ROW`**：行级触发（MySQL仅支持行级触发）\n\n- **`OLD` 伪记录**：  \n  `UPDATE/DELETE` 时访问修改/删除前的数据 (`OLD.column_name`)\n\n- **`NEW` 伪记录**：  \n  `INSERT/UPDATE` 时访问新数据 (`NEW.column_name`)\n\n- **执行顺序**（MySQL 8.0+）：\n\n  ```sql\n  FOLLOWS other_trigger  -- 在指定触发器后执行\n  PRECEDES other_trigger -- 在指定触发器前执行\n  ```\n\n## 经典应用场景与代码示例\n\n### 场景1：自动维护更新时间戳\n\n```sql\nDELIMITER $$\nCREATE TRIGGER update_timestamp\nBEFORE UPDATE ON orders FOR EACH ROW\nBEGIN\n    SET NEW.last_updated = NOW(); -- 修改新数据的值\nEND$$\nDELIMITER ;\n```\n\n### 场景2：数据审计（记录修改历史）\n\n```sql\nCREATE TABLE user_audit (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    user_id INT,\n    action VARCHAR(10),\n    old_email VARCHAR(255),\n    new_email VARCHAR(255),\n    change_time DATETIME\n);\n\nDELIMITER $$\nCREATE TRIGGER user_email_audit\nAFTER UPDATE ON users FOR EACH ROW\nBEGIN\n    IF OLD.email <> NEW.email THEN\n        INSERT INTO user_audit(user_id, action, old_email, new_email, change_time)\n        VALUES (OLD.id, 'UPDATE', OLD.email, NEW.email, NOW());\n    END IF;\nEND$$\nDELIMITER ;\n```\n\n### 场景3：强制业务规则（库存检查）\n\n```sql\nDELIMITER $$\nCREATE TRIGGER check_inventory\nBEFORE INSERT ON order_items FOR EACH ROW\nBEGIN\n    DECLARE current_stock INT;\n    \n    SELECT stock INTO current_stock \n    FROM products WHERE id = NEW.product_id;\n    \n    IF current_stock < NEW.quantity THEN\n        SIGNAL SQLSTATE '45000' -- 抛出错误阻止插入\n        SET MESSAGE_TEXT = '库存不足';\n    END IF;\nEND$$\nDELIMITER ;\n```\n\n### 场景4：级联数据同步\n\n```sql\n-- 用户删除时同步清理相关数据\nDELIMITER $$\nCREATE TRIGGER cascade_user_delete\nAFTER DELETE ON users FOR EACH ROW\nBEGIN\n    DELETE FROM user_sessions WHERE user_id = OLD.id;\n    UPDATE posts SET author_id = NULL WHERE author_id = OLD.id;\nEND$$\nDELIMITER ;\n```\n\n## 触发器管理命令\n\n```sql\n-- 查看所有触发器\nSHOW TRIGGERS [FROM db_name];\n\n-- 查看创建语句\nSHOW CREATE TRIGGER trigger_name;\n\n-- 删除触发器\nDROP TRIGGER [IF EXISTS] db_name.trigger_name;\n\n-- 临时禁用（MySQL 8.0+）\nALTER TABLE table_name DISABLE TRIGGER trigger_name; \nALTER TABLE table_name ENABLE TRIGGER trigger_name;\n```\n\n## 触发器 vs 存储过程\n\n| 特性         | 触发器                  | 存储过程             |\n| ------------ | ----------------------- | -------------------- |\n| **调用方式** | 自动由DML事件触发       | 显式通过 `CALL` 调用 |\n| **事务控制** | 与触发语句同事务        | 可独立控制事务       |\n| **参数传递** | 通过 `OLD`/`NEW` 伪记录 | 支持IN/OUT参数       |\n| **适用场景** | 数据一致性维护、审计    | 复杂业务逻辑封装     |\n| **可见性**   | 对应用透明              | 需显式调用           |\n\n## 典型错误案例\n\n**场景**：递归更新导致死循环\n\n```sql\n-- orders表上的AFTER UPDATE触发器：\nCREATE TRIGGER update_order_stats\nAFTER UPDATE ON orders FOR EACH ROW\nBEGIN\n    -- 错误：更新同表触发递归\n    UPDATE orders SET update_count = update_count + 1 \n    WHERE id = NEW.id;\nEND;\n```\n\n**解决方案**： \n使用状态标志切断递归链\n\n```sql\nCREATE TRIGGER update_order_stats\nAFTER UPDATE ON orders FOR EACH ROW\nBEGIN\n    IF @DISABLE_RECURSION IS NULL THEN\n        SET @DISABLE_RECURSION = 1;\n        UPDATE orders SET update_count = update_count + 1 \n        WHERE id = NEW.id;\n        SET @DISABLE_RECURSION = NULL;\n    END IF;\nEND;\n```","categoryId":4,"viewCount":69,"categoryName":"MySQL","author":"球接子","authorAvatar":null,"tagIds":[2,17],"tagNames":["MySQL","数据库"]}}