当前位置:首页 > 问答 > 正文

MySQL 触发器怎么用,举几个例子让你大概明白下原理和操作

MySQL触发器就像是安插在数据库表里的一个“自动监视器”加“小帮手”,它的核心思想很简单:当你在某个表上执行特定的操作(比如增加一条记录、修改一条记录、删除一条记录)之前或之后,让数据库自动地去执行一段你预先设定好的SQL代码,你不需要在应用程序里手动调用,数据库自己就会默默完成。

触发器的核心要素

要理解触发器,你得先明白它是由哪几个关键部分拧在一起的:

  1. 触发时机: 这件事是发生在之前还是之后?主要有两种:

    • BEFORE:在主要操作执行之前,先运行你的触发器代码,在插入新数据前,先检查一下数据是否合法。
    • AFTER:在主要操作执行之后,再运行你的触发器代码,在成功插入一条新订单后,自动去减少库存数量。
  2. 触发事件: 是什么操作触发了它?主要有三种:

    • INSERT:当有新的数据行被插入时。
    • UPDATE:当已有的数据行被修改时。
    • DELETE:当已有的数据行被删除时。
  3. 关联表: 这个触发器是绑在哪张表上的?每个触发器都只属于一张表。

一个完整的触发器定义听起来就像是:“在某张表上,发生某种操作(INSERT/UPDATE/DELETE)之前或之后,请执行以下SQL代码。”

触发器里的“临时变量”:NEW 和 OLD

这是理解触发器原理非常关键的一步,当触发器被激活时,数据库会给你两个临时的、虚拟的表,叫做 NEWOLD,你可以把它们想象成“快照”。

  • NEW:它存放着即将要发生刚刚发生的数据。
    • INSERT 触发器中,NEW 表示你想要插入的那条新记录,你可以通过 NEW.字段名 来访问新数据的值。
    • UPDATE 触发器中,NEW 表示修改之后的新数据。
  • OLD:它存放着变化之前的数据。
    • UPDATE 触发器中,OLD 表示修改之前的旧数据。
    • DELETE 触发器中,OLD 表示即将被删除的那条旧记录。

需要注意的是:

  • INSERT 触发器中,没有 OLD,因为插入前这条记录不存在。
  • DELETE 触发器中,没有 NEW,因为删除后这条记录就没了。

动手操作:几个例子让你明白

MySQL 触发器怎么用,举几个例子让你大概明白下原理和操作

假设我们有一个简单的电商数据库,有orders(订单表)和products(商品表)两张表。

  • products表有:product_id(商品ID), product_name(商品名), stock_quantity(库存数量)。
  • orders表有:order_id(订单ID), product_id(商品ID), quantity(订购数量)。

例子1:AFTER INSERT 触发器 —— 自动扣减库存

场景:用户下单成功后,我们希望能自动减少相应商品的库存,而不是手动去写两条SQL语句。

DELIMITER //  -- 临时改变语句结束符,因为触发器代码里有分号
CREATE TRIGGER after_order_insert
AFTER INSERT ON orders
FOR EACH ROW  -- 表示每影响一行数据就触发一次
BEGIN
    -- 当有新订单插入后,更新商品表,将库存减去新订单的数量
    UPDATE products
    SET stock_quantity = stock_quantity - NEW.quantity  -- 这里的 NEW.quantity 就是刚插入的订单中的数量
    WHERE product_id = NEW.product_id;  -- 通过商品ID找到对应的商品
END//
DELIMITER ;  -- 把语句结束符改回分号

原理:当你执行 INSERT INTO orders ... 语句时,这个触发器会自动启动,它利用 NEW.quantityNEW.product_id 这两个新插入的值,去products表里完成库存的更新,你只做了一次“下单”操作,但数据库自动帮你做了两件事。

例子2:BEFORE UPDATE 触发器 —— 数据合法性检查

场景:在修改商品价格之前,我们想检查一下新价格是否合理,比如不允许把价格改成负数。

MySQL 触发器怎么用,举几个例子让你大概明白下原理和操作

DELIMITER //
CREATE TRIGGER before_product_update
BEFORE UPDATE ON products
FOR EACH ROW
BEGIN
    -- 如果试图将价格或库存设置为负数,则强制将其设为0
    IF NEW.price < 0 THEN
        SET NEW.price = 0;  -- 注意这里直接修改了 NEW 中的值!
    END IF;
    IF NEW.stock_quantity < 0 THEN
        SET NEW.stock_quantity = 0;
    END IF;
END//
DELIMITER ;

原理:当你执行 UPDATE products SET price = -10 WHERE ... 时,这个触发器会在真正更新数据之前被触发,它检查 NEW.price(即-10)是否小于0,因为是小于0的,所以触发器内部的代码 SET NEW.price = 0; 执行了,这相当于把你要更新的值从-10改成了0,数据库才拿着这个已经被触发器修改过的 NEW 值(price=0)去执行最终的UPDATE操作,这是一种数据安全的保障。

例子3:AFTER DELETE 触发器 —— 创建审计日志

场景:当有订单被删除时,我们希望记录一条日志,记下谁在什么时候删除了哪条订单。

我们先创建一个日志表order_delete_logid(日志ID), order_id(被删订单ID), deleted_at(删除时间)。

DELIMITER //
CREATE TRIGGER after_order_delete
AFTER DELETE ON orders
FOR EACH ROW
BEGIN
    -- 向日志表插入一条记录,记录被删除的订单信息
    INSERT INTO order_delete_log (order_id, deleted_at)
    VALUES (OLD.order_id, NOW());  -- 这里的 OLD.order_id 就是被删除订单的ID
END//
DELIMITER ;

原理:当你执行 DELETE FROM orders WHERE ... 时,触发器在删除操作之后启动,它利用 OLD.order_id 来获取那条已经被删除的记录的订单号,然后将其与当前时间一起插入到日志表中,留下痕迹。

总结一下

触发器就是把一些自动化的、有依赖关系的数据库操作捆绑在一起,它的好处是保证了业务逻辑的原子性和一致性(相关操作一定会一起发生),减少了应用程序的代码量,但也要小心使用,因为过多的、复杂的触发器会让数据库的逻辑变得不透明,难以调试和维护,它就像一把双刃剑,用好了是自动化利器,用不好就是调试噩梦。