change streams 仅在事务提交后推送所有变更事件,每条带相同 txnnumber 和 lsid;不感知开启、回滚及中间操作;需数据库与集合级均启用 preandpostimages 才支持 fulldocumentbeforechange。

Change Streams 能监听事务提交后的最终状态,但不会逐条推送事务内中间操作——它只在事务 commitTransaction 完成后,一次性发出所有变更事件,且每条事件带 txnNumber 和 lsid 字段标识归属。
事务提交后,Change Streams 才触发事件
MongoDB 的 Change Streams 不感知事务的开启、回滚或中间步骤。它底层依赖 oplog,而事务的写入只有在成功提交后才会批量刷入 oplog。这意味着:
- 事务中执行的
insertOne、updateMany等操作,在commitTransaction前完全不可见于变更流 - 即使事务包含 10 次更新,只要它们属于同一事务,Change Streams 会发出 10 条独立事件,每条都带相同的
txnNumber和lsid - 若事务被
abortTransaction,oplog 中无记录,Change Streams 零事件
如何确认某条变更来自事务
检查变更事件文档中的字段即可判断:
-
operationType为insert/update/replace/delete时,若存在txnNumber字段(类型为Long),说明该操作属于某个事务 -
lsid是一个文档,含id(UUID)字段,可用于关联同一会话内的多次事务 - 注意:
transaction字段并不存在于变更事件中;不要误查这个键
fullDocument 与事务更新的兼容性
事务内的 update 操作默认只返回变更字段(updateDescription),即使设置了 fullDocument: "required",也不会自动填充更新前/后的完整文档——除非显式启用前像(pre-image)和后像(post-image):
- 数据库级开关需先执行:
db.adminCommand({ setClusterParameter: { changeStreamOptions: { preAndPostImages: { expireAfterSeconds: "off" } } } }) - 集合级启用:
db.runCommand({ collMod: "mycol", changeStreamPreAndPostImages: { enabled: true } }) - 监听时指定:
collection.watch([], { fullDocument: "required", fullDocumentBeforeChange: "required" }) - 未启用前像时,
fullDocumentBeforeChange: "required"会导致变更流报错InvalidOptions: fullDocumentBeforeChange is required but pre-images are not enabled
resume token 在事务场景下的行为
事务不影响 resume token 的有效性逻辑,但要注意两点:
- resume token 始终指向 oplog 中最后一条已处理事件的位置,无论该事件是否属于事务
- 如果在事务提交瞬间发生网络中断,恢复时从 token 继续读取,仍能拿到该事务的所有事件(只要 oplog 未被轮转覆盖)
- 不要尝试用
txnNumber或lsid做断点续传——它们不是游标位置,也不具备单调递增或全局有序性
事务和 Change Streams 的配合是“最终一致”的:你无法监听到未提交的状态,也无法跳过某次 commit 后的批量事件。真正容易被忽略的是前像/后像的两级开关——数据库级 + 集合级必须都打开,fullDocumentBeforeChange 才可能生效。











