2026/3/29 1:18:08
网站建设
项目流程
建网站上海,微商分销模式,品牌建设的目标,台州网站建站#x1f512; 事务#xff1a;最初的“一手交钱一手交货”
在业务看来#xff0c;转账就是原子操作#xff1a;A 少钱#xff0c;B 多钱。要么都成功#xff0c;要么都失败#xff0c;绝不能出现 A 扣了钱 B 没收到的情况。动作代码行数 (理想状态)描述开启事务1 行BEGI… 事务最初的“一手交钱一手交货”在业务看来转账就是原子操作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)锁住 A扣钱。准备去锁 B加钱。线程 2 (B 转给 A)锁住 B扣钱。准备去锁 A加钱。僵局线程 1 拿着 A瞪着 B。线程 2 拿着 B瞪着 A。谁也不松手谁也走不掉。后果数据库连接被这两个人占着永远不释放。后续的请求全部排队直到连接池爆满全站瘫痪。代码增加强制规定**“加锁顺序”。所有转账必须先锁 ID 小的再锁 ID 大的**。if (idA idB) { lock(A); lock(B); } else { lock(B); lock(A); }20 行逻辑判断且很容易写错。 第四关全表锁的误杀 (Table Lock)你写了个 SQLUPDATE 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 加钱”的简单逻辑变成了防丢失事务回滚。防错乱隔离级别。防卡死顺序加锁。防误伤索引优化。防分裂分布式事务补偿。为什么双十一零点下单那么卡不是因为服务器运算慢是因为成千上万个线程正在争抢那几把“数据库锁”。为了不把钱算错数据库必须让大家排队。最扎心的真相有时候为了解决死锁我们唯一的办法就是——杀掉其中一个事务超时报错告诉用户“系统繁忙请稍后再试”。这就是为什么你抢票时会莫名其妙失败那是系统为了救活其他人把你“牺牲”了。