WHAT - 事务?transaction?本地事务和分布式事务?

发布时间:2026/10/13 5:59:58
WHAT - 事务?transaction?本地事务和分布式事务? 文章目录一、什么是事务二、ACID:数据库事务的四个特性1. Atomicity:原子性2. Consistency:一致性3. Isolation:隔离性4. Durability:持久性三、ACID 的一致性与 CAP 的一致性不是一回事四、事务应该放在哪里五、本地事务为什么解决不了微服务问题六、CAP:发生网络分区时必须做出选择CP 的选择AP 的选择七、BASE:接受中间状态,换取高可用八、常见分布式事务方案1. 两阶段提交:2PC2. 三阶段提交:3PC3. TCC:Try、Confirm、CancelTryConfirmCancel4. Saga:正向操作与反向补偿5. 本地消息表与 Transactional Outbox九、一个简化的 Go Saga 示例十、补偿不等于数据库回滚十一、分布式事务必须具备的工程能力1. 幂等2. 超时3. 重试4. 状态机5. 对账与人工兜底十二、如何选择方案情况一:数据在同一个数据库情况二:业务可以异步完成情况三:资源可以预留情况四:流程很长,且每一步容易补偿情况五:必须进行原子提交,参与者都可控十三、与前端开发的类比十四、为什么前端很少谈分布式事务总结今天学习从本地事务到分布式事务:ACID、CAP、BASE、2PC、TCC 与 Saga 入门。在程序开发中,“事务”解决的是一个非常朴素但重要的问题:一组相关操作,不能只完成一半。例如用户 A 向用户 B 转账 100 元:A 扣除 100 元;B 增加 100 元。如果第一步成功,第二步失败,钱就凭空消失了。因此我们希望这两步:要么全部成功;要么全部失败;不能停在中间状态。这就是事务存在的意义。一、什么是事务事务(Transaction)可以理解为一个不可随意拆开的业务操作单元。一个事务通常经历以下过程:开始事务 ↓ 执行若干操作 ↓ 全部成功 ──→ 提交 COMMIT ↓ 任一步失败 → 回滚 ROLLBACK最常见的例子是数据库转账:BEGIN;UPDATEaccountsSETbalance=balance-100WHEREid=1ANDbalance=100;-- 程序需要检查是否真的更新了一行,-- 如果没有,说明余额不足,应当回滚。UPDATEaccountsSETbalance=balance+100WHEREid=2;COMMIT;如果第二条 SQL 执行失败,程序就调用:ROLLBACK;这样第一条 SQL 的修改也不会生效。需要注意:这两个账户必须位于同一个能够参与事务的数据库中,才能直接用这种方式处理。二、ACID:数据库事务的四个特性事务通常具备四个特性,简称 ACID。1. Atomicity:原子性事务中的操作要么全部成功,要么全部失败。例如转账:A 扣款成功 + B 收款成功 = 提交 A 扣款成功 + B 收款失败 = 回滚数据库不会把“只完成一半”当成正常结果。这里的“原子”不是指只有一条 SQL,而是指多条 SQL 在业务上被当成一个整体。2. Consistency:一致性事务执行前后,数据都必须符合业务规则和数据库约束。例如转账前:A:500 元 B:300 元 总额:800 元转账 100 元后:A:400 元 B:400 元 总额:800 元账户余额发生了变化,但“总金额不凭空增加或减少”这一业务约束仍然成立。一致性并不是数据库自动理解所有业务规则。它通常需要共同保证:数据库约束,例如唯一键、外键、非空约束;正确的事务范围;应用程序中的业务校验;并发控制。3. Isolation:隔离性多个事务并发执行时,应尽量避免互相干扰。例如两个请求同时给同一个账户扣款。如果没有正确的隔离和并发控制,就可能出现:脏读;不可重复读;幻读;丢失更新;库存或余额被扣成负数。数据库一般提供不同的隔离级别:隔离级别特点Read Uncommitted隔离最弱,可能读到别人尚未提交的数据Read Committed只能读到已经提交的数据Repeatable Read一个事务内重复读取的数据尽量保持一致Serializable效果接近事务串行执行,隔离最强但并发能力较低隔离级别越高,通常越安全,但锁竞争、等待和性能成本也可能越高。这块更具体可以阅读:WHAT - 数据库 db 事务的四个隔离级别4. Durability:持久性事务一旦成功提交,即使服务进程重启,修改通常也不会丢失。数据库一般通过日志、磁盘持久化、复制等机制实现这一点。三、ACID 的一致性与 CAP 的一致性不是一回事这两个概念都叫 Consistency,很容易混淆。ACID 的一致性:事务前后是否仍然符合业务规则和数据约束。CAP 的一致性:分布式节点对外看到的数据是否像同一份数据一样保持一致。例如:ACID 关注:转账后总金额有没有出错? CAP 关注:主节点更新余额后,其他节点能不能立刻读到相同余额?它们相关,但不是同一个概念。四、事务应该放在哪里以小程序、Web 或 App 为例,客户端可以发起转账请求,但不能由客户端自己负责事务。wx.cloud.callFunction({name:"transferBalance",data:{fromUserId:"userA",toUserId:"userB",amount:100}})真正的事务应该在云函数或后端服务中执行:consttransaction=awaitdb.startTransaction()try{constfrom=awaittransaction.collection("accounts").doc(fromUserId).get()if(from.data.balanceamount){thrownewError("余额不足")}awaittransaction.collection("accounts").doc(fromUserId).update({balance:db.command.inc(-amount)}

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询