老城梧桐街上有家瑞丰钱庄,掌柜姓陈。小时候,陈掌柜的账房只有一本总账,每一笔生意在账本上就是一行字——落笔即成。这行字要么完整地写下了,要么压根没写,绝不会出现“半个字”的尴尬。这就是我们常说的“单文档原子性”:一行记录天然完整、无法切开。可随着生意越做越大,钱庄与布庄、粮行、药铺开始联营。今天布庄要给粮行转三百两银子,账房必须同时减布庄的账、加粮行的账——两行字必须同时落笔。只减不加,账目就乱了。陈掌柜为此愁得直捋胡子。 后来,掌柜翻出一本蒙尘的旧册子,名叫“联营对账手册”——它就是 MongoDB 事务。这本手册规定:凡是牵动多本账目的事,都得走一套“发函确认、统一落账”的流程(两阶段提交),全程看着同一版账本(快照隔离),绝不能出现记一半的乱账。翻完这本手册,你会理解它是什么、如何演变、怎么运转、有哪些坑,以及什么时候压根不该用它。一句话:MongoDB 事务不是把文档数据库变成关系型数据库,而是给文档模型添上一把“多账本一致”的锁。
事务能力是你从“会写增删改查”走向“能设计可靠数据流”的关键一步。理解 MongoDB 事务,才能在订单、支付、风控等真实业务中给出既一致又高效的存储方案——这是数据工程师与后端架构师的硬通货。
目录
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
事务基础概念:一张票据,一笔记录
陈掌柜当年在账本上记录银两进出,就是一行字。笔墨落纸,这行字要么清清楚楚,要么根本没写,绝不可能出现“笔画写了一半”的账目。这就是钱庄的童子功:字要一气呵成,账才能一笔不乱。MongoDB 保存文档也是这个道理——一个文档在存储引擎中作为整体写入,单次操作要么完全生效,要么完全不生效。这个特性有一个专门的名字:单文档原子性,它是 MongoDB 一切一致性保障的地基。
可联营以后,一笔生意要同时改两本账。这时候,一行“字”就不够了,需要一套把多笔操作打包成“一单”的机制——这就是事务。事务(Transaction)把一组操作捆在一起,要么全部成功,要么像墨迹未干就被擦掉一样全部回滚。MongoDB 从 4.0 版本起正式支持多文档事务,并完整遵循 ACID:原子性(Atomicity)保证操作整体提交或回滚;一致性(Consistency)保证事务前后数据满足所有约束;隔离性(Isolation)让并发事务互不干扰;持久性(Durability)保证提交后数据不丢失。
所以陈掌柜把多笔联营账装进一个“对账单”里:要么分铺都认这一单,要么全盘抹掉。MongoDB 事务就是这张对账单,它把“多行字”变成“一单字”,保住了钱庄“落笔即成、涂改即净”的老规矩。
- 操作集合T 代表事务,花括号里是从 op₁ 到 opₙ 的所有操作,例如“布庄减银”和“粮行加银”是两个操作
- 二元结果Result(T) 表示事务的最终结果,它只可能是两个值中的一个
- 不再有中间态Committed 是提交,Aborted 是回滚,事务不存在“进行了一半”的永久状态
开发支持历程:掌柜的工具箱升级
陈掌柜的账房并不是一夜之间学会跨铺对账的。早年间联营生意少,一本总账打天下。后来联营多了,掌柜先在自家几个分号之间试行了“对账手册”;再后来分号遍布各镇,手册又升级出“总号分号统一结算”的版本;如今手册多次改版,越用越顺手。工具是慢慢换的,账房先生的胆子也是慢慢练出来的——MongoDB 对事务的支持同样是分阶段的。
2018 年 6 月,MongoDB 4.0 正式发布,首先在副本集(Replica Set)上支持多文档 ACID 事务,让单副本集内的多文档操作具备了完整的原子性与隔离性。2019 年 8 月,4.2 版本把事务扩展到分片集群(Sharded Cluster),事务可以跨越多个分片协调执行,成为真正意义上的分布式事务。此后 8.0 及更高版本持续演进:扩大事务写入大小上限、优化协调开销、完善快照和可重试写入的支持,让事务在更重的业务场景下也能落地。
这就好比掌柜的“对账手册”先是自家分号用,后来扩展成联营各号通用。手册越写越厚,但对账的底气也越来越足。MongoDB 的版本演进,正是这本手册的“修修补补”。
- 空能力集当版本号小于 4.0 时,事务能力集合为空,即不支持多文档事务
- 副本集阶段4.0 到 4.2 之间,能力集合只有副本集一项,分片集群还未覆盖
- 分片阶段从 4.2 起,能力集合同时包含副本集与分片集群,事务能力完整
副本集一致性:每本账都有复本
陈掌柜最怕两件事:火灾和盗贼。账本一旦烧了,生意全完。所以他让账房先生每本总账都抄出两三份复本,分放在不同的钱匣里——这就是钱庄的“副本集”。凡是重要的入账,先在主账本上落笔,再由账房先生誊抄到各复本上。万一主账本被毁,任取一份复本就能重建账目,生意不至于断档。
MongoDB 的副本集(Replica Set)也是同样思路:由一个主节点(Primary)承担全部写入,其他从节点(Secondary)通过复制操作日志(oplog)保持同步。如果主节点故障,剩余节点会发起选举,选出一个新主节点继续服务。三个要点值得牢记:主节点写入——所有写操作(包括事务)都必须经过主节点,它唯一决定写入顺序;从节点复制——从节点异步回放 oplog,不断追赶主节点的状态;读偏好设置——默认读主节点能拿到最新数据,而设置 readPreference 为 secondary 可以分散读压力,但可能读到稍旧版本。
有了复本,掌柜再也不怕火烧账本。但他也明白:读账的人若图快去看复本,有时会看到稍微旧一点的数字——这就是“从节点读”的取舍。想要永远最新,就得多花一点代价去读主账本。
- 复制延迟L_sync 表示某个从节点相对主节点落后了多少时间
- 非负约束从节点永远不可能比主节点“更新”,所以延迟不小于零
- 上界约束Δ 是延迟容忍上界(如心跳超时阈值),超过它说明副本已失联
快照隔离机制:看同一版老账本
联营对账最怕账目一边对一边变。陈掌柜订了一条铁规矩:一旦开启对账,所有分铺都必须照着“开账那一刻的账本副本”核对,谁也不许看中途改动的数字。这就像读今天的晨报——哪怕下午出了增刊,你手里那份晨报的内容也不会变。看报的人从不会因为增刊而困惑,因为报纸是某个时间点的“快照”。
MongoDB 事务也遵循同样的快照隔离(Snapshot Isolation):事务开始时,存储引擎为事务生成一个一致性快照,事务内的所有读操作都基于这个快照,而不是实时数据。其他事务的写入,在这个事务看来仿佛不存在——直到它自己提交。底层支撑来自 WiredTiger 存储引擎的多版本并发控制(MVCC):每条记录维护多个版本,读操作按快照时间点选取对应版本;写操作之间则通过版本号检测冲突,两个事务同时改同一文档时,后提交者会收到 WriteConflict 错误,需要捕获后重试。
有了“晨报”式快照,各分铺对账时再也不用担心隔壁突然改了数。谁要改账,就等这一单对完再改——改早了就会撞上“写冲突”这堵墙,无功而返。
- 快照版本V_tx 表示事务可见的数据版本,它来自存储引擎生成的快照
- 快照时间点τ₀ 是生成快照的那个具体时刻,比如开账的一瞬间
- 不晚于事务起点T_start(tx) 是事务开始时间,τ₀ 不能晚于它
两阶段提交:发函确认与统一落账
跨铺转账最难的不是算数,而是协同。陈掌柜的解法是“先问后写”:第一步,掌柜给涉及的每家分铺发一封确认函,写明“明日开市,布庄减银三百,粮行加银三百,贵号能否办妥?”各分铺收到后认真验账,回函“可办”或“不可办”。如果所有分铺都回“可办”,掌柜才发第二封函:“约定已定,即刻落账!”所有分铺同时下笔。但凡有一家回“不可办”,所有回函作废,一切恢复原样——这就是两阶段提交的雏形。
MongoDB 的分布式事务协调者正是这么做的。整个流程分为两个阶段:准备阶段(prepare),协调者向所有参与节点发送准备请求,各节点执行写操作并持有锁,但不提交,回复“已准备”或“不能准备”;提交阶段(commit),若全部回复“已准备”,协调者广播提交指令,各节点正式提交;否则广播中止指令,所有节点回滚。协调者(Coordinator)是核心角色:它记录事务状态,决定提交或中止,并且会把状态写入事务集合持久化,防止协调者自身崩溃后丢失决定。
陈掌柜这套“先问后写”的规矩,保证了联营各号步调一致。两阶段提交的智慧正在于此:把“能不能办”和“一起办”分成两步。宁可事前多问一句,也不要事后扯皮。
- 充要条件⟺ 表示前后双向等价,左边成立右边必成立,反之亦然
- 全称逻辑与⋀ 表示“并且”要遍历所有参与者,下标 i 从 1 到 n
- 参与者就绪Prepared(Pᵢ) 表示第 i 个参与者已经确认“已准备”
分片事务限制:跨分号的麻烦
分号开多了,麻烦也来了。陈掌柜发现,跨分号对账时,每封信都要送到不同的镇子,信使往返的脚程(网络延迟)累积起来相当可观;有的分号规矩不同,有些账目那边根本不接(功能限制);对账时间拖久了,账本一直锁着,别的新生意都做不了(超时与锁)。跨铺对账虽好,代价却实实在在。
当 MongoDB 集群做了分片(Sharding),数据被切分到多个分片上。一旦事务涉及多个分片,每个分片都要完整参与 prepare 与 commit,协调成本随分片数量增长,网络往返、锁等待、日志同步的成本叠加起来,事务性能明显下降。分片事务的典型限制包括:性能开销——涉及分片越多,两阶段协调的往返次数越多,延迟越高;功能限制——某些聚合命令和跨分片操作受限,对分片键的查询约束也更严格;超时机制——事务默认 60 秒超时(由 transactionLifetimeLimitSeconds 控制),超时自动中止;锁等待时间过长也会快速失败,保证不会无限占用资源。
陈掌柜于是定下规矩:能在一家分号办完的事,绝不劳烦第二条街。同样的道理,能设计成单分片事务的应用,就不要让 MongoDB 为“跨分片一致”多付三倍脚程钱。
- 总成本Cost(T) 表示事务 T 的整体开销,包含时间与资源消耗
- 协调者开销Cost_coord(T) 是协调者调度、状态持久化的固定成本
- 分片求和对事务涉及的每个分片 s 累加执行成本,∑ 表示求和
事务实践指南:掌柜的操作手册
陈掌柜把多年对账心得整理成一本《联营操作手册》。扉页写着三条训诫:一、回函没等到就重新发,别干等(重试);二、收到“不可办”就当即作废,从头再议(错误处理);三、对账要有专属房间,账房先生用固定桌案(会话 Session),用完马上收拾,别占着桌子(缩短事务范围)。
落到代码层面,MongoDB 事务也有同样的实践规范。第一,事务必须绑定会话(Session):通过 client.start_session() 开启会话,再调用 session.start_transaction() 开启事务,读写操作都要显式传入 session。第二,捕获可重试错误:遇到 TransientTransactionError(如写冲突、瞬态网络故障)时,应该重试的是整个事务,而不是单个操作。第三,保持事务短小:事务内只放必要的读写,杜绝耗时的外部 API 调用,避免长期占用锁和 oplog 空间。官方驱动普遍提供 withTransaction 回调,内部自动处理瞬态错误重试,开发者只需把业务操作封装进回调。
手册的道理朴素:“别干等、早作废、快收拾。”现代数据库事务也一样——代码写得越短平快,重试得越果断,系统就越稳。
- 单次失败率(1 − p) 表示单次事务失败的概率,与成功率互补
- 连续失败 k 次指数 k 表示连续失败 k 次的概率,前提是各次尝试相互独立
- 成功为补集用 1 减去全失败概率,就得到至少成功一次的概率
设计原则权衡:能一笔记清就别啰嗦
陈掌柜的祖师爷留下一句训话:“能在一页账上记清的事,绝不牵连第二本账。”单行记录天然完整、修改快、不锁别人的账;一旦动用跨铺对账,就要发函、等回音、锁账本,劳师动众。账房先生们把这句话刻在算盘上,每次想开新账本前都要先问自己:这一页真装不下吗?
这条训话对应 MongoDB 的核心设计原则:优先设计单文档模型,把相关字段内嵌进同一个文档,利用单文档原子性完成大多数业务操作;只有真正需要跨文档、跨集合甚至跨库保持一致时,才引入事务。典型的单文档场景包括:订单与订单明细——把明细作为数组内嵌进订单文档,一次写完成;用户与偏好设置——同一文档承载全部资料。必须上事务的场景包括:转账(账户 A 扣款 + 账户 B 入账)、下单(订单创建 + 库存扣减 + 积分增加)等跨集合、跨文档的一致操作。反模式警示则是“为了事务而事务”——本来可以内嵌的建模被强行拆散,再靠事务拼回去,只会平添复杂度与性能损失。
陈掌柜把祖训刻在账房门楣上,也刻进了 MongoDB 的设计哲学:单文档原子性永远是最快的路,事务是备用的桥。能走桥是本事,能不走桥才是智慧。
- 归一化设计Normalized(doc) 表示这个文档模型是理想化、简洁的
- 字段内嵌Embedded(fields, doc) 表示所有相关字段都装在同一个文档 doc 里
- 原子更新Atomic(update(doc)) 表示对 doc 的单文档更新天然具备原子性
AI 应用场景
AI 风控决策与权益的原子生效
阶段:模型推理结果落库
解决的问题:传统做法是模型回传分数后,业务系统分多条写操作更新“用户风险等级”“授信额度调整”“风控处置记录”三个独立文档。任一条失败都会造成“等级改了但额度没改”的不一致,风控等于白做。用 MongoDB 事务把三条更新包进同一事务,任何一个失败全部回滚,保证处置动作原子生效。
具体案例:某信贷平台调用反欺诈模型后,在单个 MongoDB 事务内同时更新用户的 risk_level 文档、credit_limit 文档和 audit_log 文档。模型判定为高风险时,如果额度调整写入失败,事务整体回滚,避免出现“已标注高风险却仍保留高额度”的危险状态。
AI 推荐系统的配额扣减与行为日志
阶段:推荐服务调用后的计费与数据沉淀
解决的问题:AI 推荐调用往往涉及“扣减用户配额 + 写入调用流水 + 更新 A/B 实验曝光计数”三个独立文档。单文档写入无法保证三处一致,一旦中途失败就会出现超扣或多记。事务把三者绑定,即便接口被并发请求轰炸,配额也只会扣一次,日志与计数始终匹配。
具体案例:某国民级 App 的推荐接口每次调用扣 1 积分,并写一条推荐日志,同时更新服务端 A/B 实验的曝光计数。三个操作放入同一事务。接口重试时,配合幂等去重键与事务回滚语义,保证“扣分、记日志、计曝光”三者同生共死。
AI 模型版本热切换的一致发布
阶段:模型上线与灰度发布
解决的问题:新模型上线需要同时更新模型元数据、特征映射表、监控报警配置。只改模型权重而特征映射没切过去,新旧流量会算出不一致的结果,监控也会告警失真。事务让“模型 + 特征 + 监控”三份配置在同一刻完成切换,发布过程对线上完全无感。
具体案例:某推荐团队的模型发布流程在同一个事务内完成三步写入:models 集合新增 v2 记录、features 集合切换 activeFeatureVersion、alerts 集合更新监控阈值。事务提交后,所有新请求立即使用 v2 特征流水线,老版本记录完整保留便于回滚。
Python 演示
from pymongo import MongoClient client = MongoClient("mongodb://localhost:27017")db = client["bank"]accounts = db["accounts"] def transfer(sender, receiver, amount): with client.start_session() as session: with session.start_transaction(): sender_doc = accounts.find_one({"_id": sender}, session=session) if not sender_doc or sender_doc["balance"] < amount: raise ValueError("insufficient balance") accounts.update_one( {"_id": sender}, {"$inc": {"balance": -amount}}, session=session ) accounts.update_one( {"_id": receiver}, {"$inc": {"balance": amount}}, session=session ) if __name__ == "__main__": accounts.delete_many({}) accounts.insert_many([ {"_id": "alice", "balance": 1000}, {"_id": "bob", "balance": 500} ]) transfer("alice", "bob", 200) print("normal:", [(a["_id"], a["balance"]) for a in accounts.find()]) try: transfer("alice", "bob", 99999) except ValueError as exc: print("rollback demo:", exc) print("after rollback:", [(a["_id"], a["balance"]) for a in accounts.find()])
with client.start_session() as session:开启会话,事务必须绑定会话,如同掌柜为对账单分配专属房间with session.start_transaction():在会话内开启事务,之后的读写都在“同一张对账单”里accounts.find_one({"_id": sender}, session=session)事务内的读必须传入 session,才能读取事务快照,看到开账那一刻的余额{"$inc": {"balance": -amount}}原子自减操作,配合事务保证扣款与入账同生共死raise ValueError("insufficient balance")抛出业务异常,触发 with 块自动回滚,相当于掌柜喊了一声“作废!”
常见误区
误区网上很多资料说 NoSQL 放弃 ACID 来换性能和扩展性,所以 MongoDB 也做不了事务,只能靠应用层自己补偿。
正解MongoDB 从 4.0 起就在副本集上支持多文档 ACID 事务,4.2 起支持分片集群上的分布式事务。NoSQL 是一个宽泛的分类,不是“完全没有事务”的同义词。这就好比钱庄虽不用朝廷银票结算中心那套制度,但联营分号之间照样有自己的对账章程,章程同样严谨。
为何常见:NoSQL 早期宣传确实以“放松事务换取扩展性”为主打,这类旧印象在社区里流传太广,很多人的知识还停留在 3.x 时代。
误区一个订单文档要同时改状态、改金额、改物流信息,这么多字段一起变,是不是必须开事务?
正解这属于“多字段更新”,但仍是单文档操作。MongoDB 在存储引擎层面保证单文档更新天然原子,不需要事务。事务只用在跨文档、跨集合或多个文档必须同生共死的场景。就像在一行账目上改数字,不管改几栏,都还是那一行,一支笔就能写完。
为何常见:把“多字段”和“多文档”混为一谈,因为关系型数据库里一行多列由行锁保证,而 JSON 文档的嵌套字段容易让人误以为各自独立。
误区既然数据库支持事务了,那所有读取不都应该能看到最新的值吗?
正解事务提供的是快照隔离——事务内看到的是开始时刻的快照,而不是实时最新值。事务外的普通读默认读主节点,但如果设置了 readPreference 为 secondary,仍可能读到落后数据。事务保证一致性,不代表全局实时可见。这就像你手里那份晨报是“那一刻的新闻”,增刊出了也与你无关。
为何常见:把“一致性”误解为“实时性”,这是分布式系统里最经典的概念混淆,尤其容易被关系型数据库的事务经验带偏。
误区反正都是数据库操作,跨分片事务无非多走几步消息,用户根本感知不到差异。
正解跨分片事务的每次写入都要在多个分片上完整参与 prepare/commit,网络往返、锁等待、协调者状态落盘的累积开销很大,事务涉及的文档还会产生额外的路由与调度限制。实际生产中,跨分片事务的延迟可能是单分片事务的数倍甚至更高。一分钱一分货,跨铺对账当然比单本记账贵得多。
为何常见:本地单机事务很快,让人误以为分布式协调只是“多走两步”,低估了网络与共识的工程代价。
误区代码里 catch 到异常,把同一段代码重新跑一遍就能解决所有问题,反正驱动会自动重试。
正解重试只对一部分错误有效。TransientTransactionError(写冲突、瞬态网络故障)值得重试;而“余额不足”这类业务异常重试一万次也没用,甚至可能把一次成功的操作重复执行变成重复扣款。重试必须配合幂等键或业务校验,否则会把“部分成功”变成“重复操作”。就像回函说“不可办”,你重发一百遍确认函,人家还是不可办。
为何常见:看到官方驱动有 withTransaction 自动重试,就以为所有异常都能自动恢复。实际上自动重试只帮助瞬态错误,业务语义错误永远要靠人判断。
面试题
Q1. 在 MongoDB 中引入多文档 ACID 事务的版本是?
- A.3.6 版本
- B.4.0 版本← 正确答案
- C.4.2 版本
- D.5.0 版本
答案:B。MongoDB 4.0(2018 年 6 月)首次在副本集上支持多文档 ACID 事务;4.2 是把事务扩展到分片集群,而不是首次引入。就像对账手册先在自己分号试行,后推广到全部分号——4.0 落地,4.2 放大,记忆时抓住“先副本后分片”的顺序。
Q2. 单文档更新操作具备天然原子性的根本原因是?
- A.文档经过分布式锁保护
- B.文档被存储引擎单点写入← 正确答案
- C.副本集同步保证一致性
- D.客户端请求串行到达
答案:B。单文档原子性来自存储引擎(WiredTiger)把整个文档作为一次写入单元,要么完全写入要么完全不写入,无需任何分布式协调。分布式锁和副本集同步都发生在多节点场景,不是“单文档原子”的根源;客户端请求串行到达也只是并发模型,与原子性无关。
Q3. 关于 MongoDB 事务的快照隔离,正确的说法是?
- A.事务每次读都读取最新提交的数据
- B.事务开始时获取一致性快照← 正确答案
- C.事务提交时才生成数据快照
- D.快照对所有并发事务共享
答案:B。事务开始时,存储引擎为它生成一致性快照,整个事务期间的读都基于这份快照,这也是“晨报”式体验的来源。A 是实时读而非快照读;C 颠倒了时序;D 错在快照按事务隔离,互不共享。
Q4. 两阶段提交中,协调者允许广播提交的充要条件是?
- A.有半数以上参与者回复已准备
- B.所有参与者都回复已准备← 正确答案
- C.至少一个参与者回复已准备
- D.由主节点单方面作出决定
答案:B。两阶段提交是“全票通过”机制:所有参与者都回复“已准备”才可提交,任何一个说“不可办”就整体中止。这就像陈掌柜发确认函,必须所有分号都回“可办”,才能统一落账;半数通过或单方面决定都会破坏跨铺一致性。
Q5. MongoDB 4.2 版本在事务方面的里程碑是?
- A.首次引入多文档事务机制
- B.支持分片集群上的事务← 正确答案
- C.取消事务默认超时时间
- D.移除事务的协调者角色
答案:B。4.2 把事务从副本集扩展到分片集群,使跨分片分布式事务成为生产可用能力。首次引入多文档事务是 4.0;取消超时和移除协调者都不符合事实——超时与协调者恰恰是分布式事务的基石,不可能被移除。
Q6. 两阶段提交中,若某个参与者回复“无法准备”,协调者会?
- A.继续等待其他参与者回复
- B.向全部参与者广播提交指令
- C.广播中止指令并回滚事务← 正确答案
- D.只提交已回复准备好的节点
答案:C。只要有一家分号说“不可办”,整单生意就作废。协调者会广播中止指令,所有参与者回滚已做的写入,恢复到事务开始前的状态。继续等待毫无意义,提交指令更不可能发出,因为全票通过的前提已经不成立了。
Q7. 以下关于跨分片事务性能的描述,错误的是?
- A.事务协调涉及更多网络往返
- B.锁的持有时间通常更长更久
- C.性能与单分片事务基本一致← 正确答案
- D.协调者的调度开销明显增加
答案:C。跨分片事务的成本公式是协调成本加各分片成本之和,分片越多开销越大,性能绝不可能与单分片事务“基本一致”。A、B、D 都是跨分片协调的真实代价。用钱庄比喻:跨三镇对账的脚程和锁账时间,一定比自家一间分号核算贵得多。
Q8. MongoDB 事务遵循的 ACID 特性包含哪些?
- A.原子性(Atomicity)← 正确答案
- B.一致性(Consistency)← 正确答案
- C.可用性(Availability)
- D.持久性(Durability)← 正确答案
答案:ABD。ACID 是原子性、一致性、隔离性、持久性四个英文首字母的缩写,对应 A、B、D。可用性(Availability)属于 CAP 定理中的概念,不是 ACID 的组成部分。ACID 关心单事务的可靠性,CAP 关心分布式系统的取舍,二者常被混淆。
Q9. 以下属于 MongoDB 事务限制的是?
- A.事务默认存在 60 秒超时← 正确答案
- B.单事务写入限制为 16MB← 正确答案
- C.事务内可以做耗时的外部请求
- D.事务只能操作单个集合文档
答案:AB。MongoDB 事务默认 60 秒超时(可调),且单事务的写操作量默认上限为 16MB,这两项都是硬限制。事务内做耗时的外部请求违背“短事务”最佳实践,并非支持的能力;事务可以跨多个集合操作,D 是错误的说法。
Q10. 编写健壮的 MongoDB 事务代码,推荐的实践有?
- A.尽量缩短事务的运行时间← 正确答案
- B.事务内放入最少必要操作← 正确答案
- C.忽略可重试的错误直接返回
- D.捕获瞬态错误后重试整个事务← 正确答案
答案:ABD。事务越短,锁占用越少,写冲突概率越低,所以 A、B 都正确;遇到 TransientTransactionError(写冲突、瞬态网络故障)应该重试整个事务,D 正确。C 忽略错误会导致业务不一致,是明显的反模式。