“订单下单 + 库存锁定”的完整事务处理逻辑
下面是一个完整实战案例,演示如何在 PHP + MySQL(使用 PDO) 中,使用事务机制确保订单下单与库存锁定的原子性和数据一致性。这个模式适用于各种电商平台或库存管理系统。
实战目标
- 用户下单
- 系统生成订单记录
- 检查库存是否充足
- 扣减库存数量
- 所有步骤必须一致成功或全部失败
数据库结构示例(MySQL)
-- 商品表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
stock INT NOT NULL
) ENGINE=InnoDB;
-- 订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT NOT NULL,
quantity INT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
确保使用 InnoDB 引擎,否则事务将不起作用。
下单逻辑分析(核心业务)
- 开启事务
- 查询当前库存
- 如果库存充足,插入订单记录
- 更新库存数量
- 提交事务
- 若任意步骤失败,则回滚
完整 PHP 代码(使用 PDO + 事务)
<?php
$pdo = new PDO("mysql:host=localhost;dbname=test", "root", "", [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$productId = 1; // 商品ID
$buyQuantity = 2; // 购买数量
try {
// 开启事务
$pdo->beginTransaction();
// 查询当前库存
$stmt = $pdo->prepare("SELECT stock FROM products WHERE id = :id FOR UPDATE");
$stmt->execute([':id' => $productId]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
throw new Exception("商品不存在");
}
if ($product['stock'] < $buyQuantity) {
throw new Exception("库存不足");
}
// 插入订单
$insertOrder = $pdo->prepare("INSERT INTO orders (product_id, quantity) VALUES (:pid, :qty)");
$insertOrder->execute([':pid' => $productId, ':qty' => $buyQuantity]);
// 更新库存
$updateStock = $pdo->prepare("UPDATE products SET stock = stock - :qty WHERE id = :pid");
$updateStock->execute([':qty' => $buyQuantity, ':pid' => $productId]);
// 提交事务
$pdo->commit();
echo "✅ 下单成功";
} catch (Exception $e) {
$pdo->rollBack();
echo "❌ 下单失败:" . $e->getMessage();
}
测试方法
你可以用以下方式初始化商品数据:
INSERT INTO products (name, stock) VALUES ('手机', 10);
然后多次访问下单代码,模拟库存扣减。库存不足时会自动失败并回滚。
安全性与并发说明
- 使用了
SELECT ... FOR UPDATE来锁定行级记录,避免并发下多用户同时扣减导致超卖 - 所有逻辑都在事务中完成,保证了操作的原子性与一致性
可扩展性建议
| 模块 | 建议 |
|---|---|
| 多商品下单 | 扩展 orders 表结构 + orders_items 子表 |
| 分布式架构 | 考虑使用分布式事务或 TCC/Saga 模式 |
| 高并发优化 | 增加库存缓存、消息队列异步处理 |
📘 官方参考链接
更多详细内容,请关注其他相关文章!