MongoDB单机模式下事务命令被服务端硬性拒绝,因事务依赖副本集的oplog等组件,启动时未初始化;必须通过--replSet参数启用副本集身份并执行rs.initiate()激活,且readConcern和writeConcern须显式设为"majority"。

事务命令直接被服务端拒绝,不是配置没开而是根本没加载模块
MongoDB 从 4.0 开始,startTransaction()、commitTransaction() 这类命令在单机模式下不是“不生效”,而是服务端协议层硬性拦截——返回 CommandNotSupportedOnServer 或 Transaction numbers are only allowed on a replica set member or mongos。这不是驱动或代码问题,是 mongod 启动时压根没初始化事务编号分配器、oplog 写入器、prepare/commit 日志等核心组件。
验证很简单:rs.status() 在单机上必然报 no replset config has been received;db.runCommand({ replSetGetStatus: 1 }) 同样失败。这两个命令比查版本号更能说明问题:没有副本集身份,事务引擎连启动机会都没有。
加 --replSet 参数不是“假装”,而是真正启用 oplog 和选举框架
--replSet rs0 的作用远不止改个名字。它让 mongod 进程以副本集成员身份启动,从而激活以下机制:
- 创建并维护
local.oplog.rs集合,所有事务写入都先落这里 - 启用心跳、状态机和
txnNumber分配器,用于冲突检测和回滚跟踪 - 支持
readConcern: "snapshot"和writeConcern: { w: "majority" }的语义校验
不加这个参数,storage.journal.enabled: true 或 --enableMajorityReadConcern 都无效——它们解决的是持久化或读关注级别,不是事务准入开关。
rs.initiate() 是必须的显式“激活”动作,不是可选步骤
只加 --replSet 启动,mongod 只是“准备好当副本集成员”,但 local.system.replset 集合仍为空,集群未形成。此时 rs.status() 会卡在 STARTUP 或报错 replSet couldn't initiate。
必须连上后执行:
rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] })
注意三点:
- 必须用
localhost,不能用127.0.0.1,否则驱动解析主机名失败会导致事务 session 创建被拒 - Windows 服务方式安装时,
--replSet必须写进服务注册命令(如mongod --install --replSet rs0),光改配置文件无效 - 如果之前失败过,
local.system.replset可能残留旧配置,需停服务、单机模式连local库并执行db.system.replset.drop()和db.oplog.rs.drop()清理
事务能 start 不代表 commit 能成功,readConcern 和 writeConcern 必须显式指定
副本集就绪后,session.startTransaction() 成功了,但紧接着 commitTransaction() 很可能失败。常见错误包括:
-
readConcern: "local"不被允许,必须设为"majority"(4.2+ 推荐)或"snapshot"(4.0+) -
writeConcern: { w: 1 }会触发Transaction numbers require a majority错误,必须用{ w: "majority" } - Node.js 驱动示例:
session.startTransaction({ readConcern: { level: "majority" }, writeConcern: { w: "majority" } })
这些不是可选优化项,是 MongoDB 强制校验的事务前提条件。漏掉任意一个,事务操作会静默降级或直接报错。

















