news 2026/6/25 16:35:49

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

作者头像

张小明

前端开发工程师

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/6/21 12:15:58

cy5.5-Fructose-6-phosphate,cy5.5-果糖-6-磷酸

Cy5.5-Fructose-6-phosphate&#xff08;Cy5.5-果糖-6-磷酸&#xff09;是由荧光染料Cy5.5与生物分子**果糖-6-磷酸&#xff08;Fru-6-P&#xff09;**偶联形成的化合物。果糖-6-磷酸是糖酵解途径中的重要中间产物&#xff0c;广泛参与细胞内的能量代谢过程。Cy5.5作为一种深红…

作者头像 李华
网站建设 2026/6/22 10:23:24

从千元到近亿,“死了么”App为何刷爆全网?

2026 年刚开局&#xff0c;互联网就被一个名字不太吉利的 APP 刷了屏——“死了么”&#xff08;1 月 13 日官方公布其后续将启用全球化品牌名 Demumu&#xff09;。没有算法加持&#xff0c;没有 AI 炫技&#xff0c;甚至没有花一分钱推广&#xff0c;这个功能简单到近乎简陋的…

作者头像 李华
网站建设 2026/6/18 21:08:36

Scrapy LinkExtractor参数详解与复杂链接提取

Scrapy 作为 Python 生态中最强大的爬虫框架之一&#xff0c;其链接提取功能是实现深度爬取、整站爬取的核心基础。LinkExtractor&#xff08;位于scrapy.linkextractors import LinkExtractor&#xff09;是 Scrapy 提供的专门用于提取页面中链接的工具类&#xff0c;它封装了…

作者头像 李华
网站建设 2026/6/14 22:33:09

基于STM32智能出租车计价器分时计费设计60X(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32智能出租车计价器分时计费设计60X(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码产品功能描述&#xff1a; 本系统由STM32F103C8T6单片机核心板、1.44寸TFT彩屏、电机驱动电路、霍尔传感器、蜂鸣器报警、按键电路及电…

作者头像 李华
网站建设 2026/6/14 19:09:04

、STM32智能交流电压电流+有功功率+功率因数+频率+无功功率+视在功率(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

24-035、STM32智能交流电压电流有功功率功率因数频率无功功率视在功率(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码产品功能描述&#xff1a; 本设计由STM32F103C8T6单片机核心板无线模块可选TFT1.44寸液晶屏交流采集模块组…

作者头像 李华