MongoDB事务无硬编码条数限制,但安全规模受锁超时(默认60秒)、WiredTiger快照内存占用、单文档16MB BSON上限、分片路由约束等隐性瓶颈制约;超限将导致卡死、OOM或静默失败。

MongoDB事务没有“一次最多操作多少条文档”的硬编码数字限制,但实际能安全执行的规模受多个隐性瓶颈共同约束——超了不是报错码,而是卡死、超时、OOM 或 DocumentTooLarge。
为什么事务里 insertOne 1000 次就可能失败
这不是 MongoDB 主动拦住你,而是底层机制在默默报警:
-
maxTransactionLockRequestTimeoutMillis默认 60000(60 秒),事务内每多一条写,锁持有时间就线性增长;1000 条写若涉及索引更新或文档膨胀,很容易触发TransactionTooOld - WiredTiger 必须为整个事务维护一致性快照,修改文档越多,内存中 snapshot 和 journal 缓冲占用越大;实测单事务修改超 200 个中等大小文档(如每条 50KB),就可能触发 OOM
- 事务内所有操作仍受单文档
16MBBSON 上限约束——哪怕只调一次insertOne,只要序列化后超限,立刻报DocumentTooLarge(错误码 10334) - 分片集群下,事务所有操作必须路由到同一 shard;跨 shard 写会直接被拒绝,不报错,而是静默失败或返回
ShardKeyNotFound
分批处理时该按什么粒度切事务
别迷信“1000 条一批”,那只是 insertMany 的自动拆分阈值,和事务无关。真实分批要看业务语义和压测结果:
- 以业务逻辑单元为单位:一个订单含
orders、order_items、payments三张表,这 3 条必须包进同一次session.withTransaction(),不能拆 - 每批显式设
maxTimeMS:例如session.startTransaction({ maxTimeMS: 30000 }),防止某批卡死拖垮整体 - 避免固定数量分片:用
{ _id: { $gte: startId, $lt: endId } }而非skip/limit,后者易漏数据且无法利用索引 - 监控长事务:运行
db.currentOp({ "secs_running": { $gt: 10 } }),快速定位卡住的事务
哪些操作根本没必要进事务
事务开销全花在多文档原子性上,不是所有写都需要它:
-
$inc、$push到小数组、单文档updateOne本身是原子的,裹进事务纯属浪费资源 - 日志类(
audit_log)、统计类(user_activity)、通知类写入,应移出事务,改用change stream或异步 job 补偿 - 跨集合强一致场景(如扣库存 + 生单)才需事务;若库存服务已用分布式锁隔离,MongoDB 层可降级为单文档写
-
$merge、$out、$lookup关联巨量数据,这些聚合阶段不支持事务,强行塞进去会直接报错
真正卡住事务规模的,往往不是总条数,而是某个文档体积、某个阶段的中间态膨胀、或者没建索引就 $sort 千万级数据——这些细节比“理论上支持多少”更决定你能不能跑通。


















