news 2026/4/23 16:03:13

为什么双十一零点你抢不到票?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么双十一零点你抢不到票?

🔒 事务:最初的“一手交钱一手交货”

在业务看来,转账就是原子操作:A 少钱,B 多钱。要么都成功,要么都失败,绝不能出现 A 扣了钱 B 没收到的情况。

动作代码行数 (理想状态)描述
开启事务1 行BEGIN TRANSACTION;
扣钱1 行UPDATE account SET balance = balance - 100 WHERE id = A;
加钱1 行UPDATE account SET balance = balance + 100 WHERE id = B;
提交1 行COMMIT;

总计:4 行 SQL。

程序员觉得这逻辑完美无缺。直到并发(Concurrency)这个恶魔降临。


⚛️ 第一关:原子性的代价 (Atomicity)

刚上线,服务器断电了。

  • A 的钱扣了。
  • 电断了。
  • B 的钱没加上。
  • 结果:100 块钱凭空蒸发了。用户打爆了客服电话。

代码增加:你必须引入复杂的回滚机制 (Rollback)。在代码里包裹try-catch,一旦第二步报错,必须把第一步扣的钱吐出来。如果数据库本身挂了,还得靠日志(Redo Log/Undo Log)恢复。+30 行异常处理逻辑。


👻 第二关:脏读与幻读的迷魂阵 (Isolation)

为了快,数据库允许很多人同时读写。

  • 脏读:事务甲正在改 A 的余额(还没提交),事务乙读取了 A 的余额。结果事务甲回滚了!事务乙读到的是假数据。
  • 幻读:事务甲查了一下:“现在有 3 个订单”。事务乙突然插进去新增了一个订单。事务甲一回头:“怎么变成 4 个了?见鬼了?”

代码增加:你开始调整隔离级别 (Isolation Level)

  • 级别越高(如 Serializable),数据越安全,但速度越慢(排队)。
  • 级别越低(如 Read Committed),速度越快,但全是 Bug。
    你需要在性能和数据准确性之间走钢丝。+N 行配置和锁策略分析。

🔫 第三关:死锁——墨西哥僵局 (Deadlock)

这是最经典的灾难。两个线程同时操作,互相卡死。

场景:两个人同时转账。

  • 线程 1 (A 转给 B):
  1. 锁住 A(扣钱)。
  2. 准备去锁 B(加钱)。
  • 线程 2 (B 转给 A):
  1. 锁住 B(扣钱)。
  2. 准备去锁 A(加钱)。

僵局:

  • 线程 1 拿着 A,瞪着 B。
  • 线程 2 拿着 B,瞪着 A。
  • 谁也不松手,谁也走不掉。

后果:
数据库连接被这两个人占着,永远不释放。后续的请求全部排队,直到连接池爆满,全站瘫痪

代码增加:强制规定**“加锁顺序”。所有转账必须先锁 ID 小的,再锁 ID 大的**。
if (idA < idB) { lock(A); lock(B); } else { lock(B); lock(A); }
+20 行逻辑判断,且很容易写错。


🚧 第四关:全表锁的误杀 (Table Lock)

你写了个 SQL:UPDATE account SET balance = balance - 100 WHERE name = '张三';
注意:你用了name,但name字段没有索引

数据库的逻辑:
“你要锁张三?但我不知道张三在哪行啊。为了防止你改错,我先把整张表锁起来吧!”

后果:
一个人买牛奶(锁表),导致全超市的人都不能结账。
本来是行级锁(Row Lock),瞬间升级为表级锁(Table Lock)。系统吞吐量从 10000 QPS 跌到 1 QPS。

代码增加:疯狂补索引,做 Explain 分析,严禁在事务中使用非索引字段作为条件。+DBA 的咆哮。


🕸️ 第五关:分布式事务的深渊 (Distributed Transaction)

系统做大了,拆成了微服务。

  • 账户服务在数据库 A。
  • 积分服务在数据库 B。
  • 本地事务(@Transactional)失效了!因为它管不了两个数据库。

后果:
钱扣了(库 A),积分没加(库 B 挂了)。
你不能回滚库 A,因为那是别人的库。

代码增加:欢迎来到地狱。

  • TCC (Try-Confirm-Cancel):每个接口都要写三个方法:预留、确认、撤销。
  • Seata / 2PC:引入沉重的分布式事务框架。
  • 最终一致性:写消息队列,不断重试,告诉用户“处理中”,其实是后台在疯狂补救。
    代码量翻倍,逻辑复杂度指数级上升。

💡 结论:锁是必要的恶

最终,那个理想中“A 减钱,B 加钱”的简单逻辑,变成了:

  • 防丢失:事务回滚。
  • 防错乱:隔离级别。
  • 防卡死:顺序加锁。
  • 防误伤:索引优化。
  • 防分裂:分布式事务补偿。

为什么双十一零点下单那么卡?
不是因为服务器运算慢,是因为成千上万个线程正在争抢那几把“数据库锁”
为了不把钱算错,数据库必须让大家排队。

最扎心的真相:
有时候为了解决死锁,我们唯一的办法就是——杀掉其中一个事务(超时报错),告诉用户:“系统繁忙,请稍后再试”。
这就是为什么你抢票时会莫名其妙失败,那是系统为了救活其他人,把你“牺牲”了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:38:33

黄金票据是什么

黄金票据&#xff08;Golden Ticket&#xff09;&#xff0c;在内网渗透中&#xff0c;是最高权限的象征&#xff0c;是通往域控制器&#xff08;DC&#xff09;的万能钥匙。为了让你理解它&#xff0c;我们先不讲枯燥的 Kerberos 协议&#xff0c;我们来打个比方。一、 通俗比…

作者头像 李华
网站建设 2026/4/23 13:11:43

vue3基于Django的校园二手物品交易系统设计与实现49895951

目录 摘要核心功能技术实现创新点 开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 摘要 该系统基于Vue3与Django框架&#xff0c;设计并实现了一个校园二手物品交易平台&#xff0c;旨在解…

作者头像 李华
网站建设 2026/4/23 14:31:55

基于51/STM32单片机锂电池蓄电池充电容量过充过压保护无线设计(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

10-锂电池蓄电池充电 基于51/STM32单片机锂电池蓄电池充电容量过充过压保护无线设计(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码锂电池充电电压检测电流检测AD转换过压保护LCD1602液晶C51-63 蓄电池充电器-220交流整流滤波…

作者头像 李华
网站建设 2026/4/23 13:19:19

基于STM32水位检测PID控制系统APP设计183(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32水位检测PID控制系统APP设计183(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码产品功能描述&#xff1a; 本系统由STM32F103C8T6单片机核心板、1.44寸TFT彩屏、&#xff08;无线蓝牙/WIFI模块-可选&#xff09;、水位…

作者头像 李华
网站建设 2026/4/15 18:41:53

大模型学习指南:10个核心概念详解,收藏学习不走弯路

这篇文章是写给AI初学者的指南&#xff0c;详细解释了10个让小白头疼的大模型核心概念&#xff1a;Token、Context Window、Temperature等。作者用通俗易懂的比喻和实例&#xff0c;将复杂技术概念转化为普通人能理解的内容&#xff0c;帮助读者真正掌握AI时代的入门知识。文章…

作者头像 李华