在电商系统的订单流转过程中,库存的自动增减是核心需求之一。当用户下单时库存需要扣减,订单取消或退款时库存需要回滚,使用MySQL触发器可以将这些库存操作逻辑下沉到数据库层,减少业务代码的重复编写。

触发器基础概念
MySQL触发器是附着在表上的数据库对象,当表发生INSERT、UPDATE、DELETE操作时,会自动触发预设的逻辑。触发器分为BEFORE和AFTER两种触发时机,分别对应操作执行前和执行后触发。
对于库存场景,我们通常使用AFTER触发器,确保业务数据写入成功后再执行库存变更,避免业务操作失败但库存已经修改的问题。
电商库存表结构设计
首先我们需要准备两张核心表,分别是商品库存表和订单明细表,表结构如下:
-- 商品库存表
CREATE TABLE product_stock (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT NOT NULL COMMENT '商品ID',
stock_num INT NOT NULL DEFAULT 0 COMMENT '当前库存数量',
UNIQUE KEY uk_product_id (product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品库存表';
-- 订单明细表
CREATE TABLE order_item (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id VARCHAR(32) NOT NULL COMMENT '订单ID',
product_id INT NOT NULL COMMENT '商品ID',
buy_num INT NOT NULL DEFAULT 1 COMMENT '购买数量',
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 1-正常 2-取消 3-退款'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';
下单时自动扣减库存的触发器
当用户下单插入订单明细记录时,我们需要自动扣减对应商品的库存。这里创建AFTER INSERT触发器:
DELIMITER //
CREATE TRIGGER trg_order_item_after_insert
AFTER INSERT ON order_item
FOR EACH ROW
BEGIN
-- 只有订单明细状态为正常时才扣减库存
IF NEW.status = 1 THEN
UPDATE product_stock
SET stock_num = stock_num - NEW.buy_num
WHERE product_id = NEW.product_id;
END IF;
END //
DELIMITER ;
触发器中通过NEW关键字获取新插入的订单明细数据,判断状态为正常后才执行库存扣减,避免无效订单影响库存。
订单取消或退款时自动回滚库存
当订单取消或者退款时,订单明细的状态会更新为取消或退款,此时需要回滚对应的库存。我们创建AFTER UPDATE触发器:
DELIMITER //
CREATE TRIGGER trg_order_item_after_update
AFTER UPDATE ON order_item
FOR EACH ROW
BEGIN
-- 只有状态从正常变为取消或退款时才回滚库存
IF OLD.status = 1 AND (NEW.status = 2 OR NEW.status = 3) THEN
UPDATE product_stock
SET stock_num = stock_num + OLD.buy_num
WHERE product_id = OLD.product_id;
END IF;
END //
DELIMITER ;
这里通过OLD关键字获取更新前的订单明细数据,确保回滚的是原本扣减的库存数量,避免数量错误。
方案注意事项
- 触发器逻辑要尽量简单,避免复杂的计算和跨表操作,否则会影响数据库性能
- 库存扣减前建议添加库存校验逻辑,避免库存出现负数,可在触发器中添加判断:
IF (SELECT stock_num FROM product_stock WHERE product_id = NEW.product_id) >= NEW.buy_num THEN - 触发器是数据库层面的逻辑,排查问题时需要同时关注业务代码和触发器逻辑,建议做好相关日志记录
- 如果系统并发量较高,建议结合分布式锁或者乐观锁使用,避免超卖问题
适用场景分析
这种基于触发器的库存自动增减方案适合中小型电商系统,业务场景相对简单,不需要复杂的库存规则。如果系统有预售、拼团、多仓库库存等复杂场景,建议还是将库存逻辑放在业务层实现,方便后续扩展和维护。