Administrator
Administrator
发布于 2026-10-27 / 0 阅读
0
0

数据库入门到初级(17):事务入门:为什么下单不能只执行一条 SQL

数据库入门到初级 · 第 17/22 篇。实验口径:MySQL 8.4、InnoDB、utf8mb4。案例:小型商城。

下单不只是往订单表里插一行。至少还要确认商品可售、扣减库存、创建订单、写入明细。如果扣了库存却没建成订单,库存就少了;如果订单建成却没扣库存,又可能卖超。事务把这些必须一起成功的修改放进一个工作单元。

1. 事务的直觉:要么一起完成,要么撤销

START TRANSACTION;
UPDATE products SET stock = stock - 1
WHERE id = 1 AND is_on_sale = 1 AND stock >= 1;
SELECT ROW_COUNT() AS changed_products;

先单独执行上面这段。只有 changed_products=1 才继续下段;否则立即 ROLLBACK 并结束。SQL 脚本不会因为返回 0 行就自动跳到回滚,应用必须检查并做分支。

INSERT INTO orders (user_id, status, total_amount)
VALUES (1, 'pending', 199.00);
SET @new_order_id = LAST_INSERT_ID();

INSERT INTO order_items
  (order_id, product_id, product_name, unit_price, quantity)
VALUES (@new_order_id, 1, '机械键盘', 199.00, 1);

SELECT stock FROM products WHERE id = 1;
SELECT * FROM orders WHERE id = @new_order_id;
ROLLBACK;

练习基于原始样例,期间会看到库存从 20 变成 19,并看到新订单;最后回滚后库存恢复,订单和明细也不会保留。价格在这里固定为样例的 199,真正应用应读取并验证当前价格,第 21 篇会给出程序示例。

下单事务的提交与回滚边界

2. ACID 不必硬背,放进例子理解

特性 本例中的直观含义
原子性 Atomicity 事务内需要完成的修改作为整体提交或撤销
一致性 Consistency 合法状态经过事务仍满足已经定义的约束和业务规则
隔离性 Isolation 多个事务并发时,按所选隔离级别与锁规则相互影响
持久性 Durability 成功提交后的保存由日志、存储和相关配置保障

一致性不是数据库替你发现所有业务错误。把订单金额写错,只要没有相应检查,事务也可能成功提交。持久性也不是“任何硬件故障都绝不会丢数据”,实际保障与刷盘配置、存储系统及故障场景有关。

3. 自动提交容易让人误会

SELECT @@autocommit;

许多命令行连接默认开启自动提交,每条普通修改语句单独提交。显式 START TRANSACTION 后,直到 COMMIT 或 ROLLBACK 才结束当前事务。

不同驱动可能设置不同默认值,所以应用不能凭命令行经验猜。尤其使用连接池时,要知道连接归还前是否清理了未完成事务,以及下一次借出的会话有哪些设置。

4. 一条语句失败,不代表整个事务已经撤销

例如第二条插入因为唯一约束失败,前面成功的库存修改可能仍留在当前事务中。应用如果继续提交,就可能把残缺结果保存下来。正确方式是在必要步骤失败后,明确回滚整个业务事务。

有些错误(例如死锁导致事务被选为牺牲者)会让 InnoDB 回滚事务;另一些错误只影响当前语句。不要用一个笼统假设覆盖所有错误,应统一处理异常并保证连接状态清楚。

5. 事务应该短,而且使用同一连接

库存更新、订单和明细写入必须使用同一事务连接。不能在连接 A 扣库存、连接 B 建订单,却以为一次 COMMIT 能提交两边。

事务期间不要等待用户确认、发送耗时邮件或调用不确定延迟的外部接口。数据库事务也不能直接把外部支付平台的扣款一起回滚;跨系统流程需要进一步的幂等、消息和补偿设计。

本例把创建待支付订单理解为预留库存。完整商城还需要超时释放、取消回补和支付状态协调,本篇只演示数据库内的原子修改。

练习与答案

练习:故意让明细数量为 0,再尝试插入,会发生什么? 检查约束会拒绝该明细;随后应主动执行 ROLLBACK,而不是继续提交之前的扣库存结果。

练习:回滚后新订单编号跳过去了,是否说明回滚失败? 不是。自增编号可能不回收,判断是否撤销应查询记录和库存,而不是要求编号连续。

延伸阅读


上一篇:第 16 篇 · 系列目录 · 下一篇:第 18 篇


评论