MongoDB 4.0+事务中禁止执行db.createCollection(),必须在事务外预先创建集合;事务仅支持对已存在集合的读写,且需通过原生collection实例(而非Mongoose Model)操作,并确保复制集状态稳定。

事务中不能执行 db.createCollection()
MongoDB 4.0+ 的事务机制明确禁止在事务块内创建集合(包括 db.createCollection() 或隐式插入触发的自动建集)。这不是 bug,而是设计约束:事务只允许对**已存在**的集合进行读写操作。一旦尝试在 session.withTransaction() 内调用 db.createCollection(),会直接报错 CommandNotSupported: createCollection is not supported in transactions。
db.createCollection() 必须在事务外提前执行
所有参与事务的集合,必须在开启事务前就已存在。常见做法是:
- 启动服务时,用脚本批量执行
db.createCollection("orders")、db.createCollection("payments")等 - 在部署流程中,把集合创建和
$jsonSchema验证规则一起固化为初始化步骤 - 避免依赖“第一次
insertOne()自动建集”——这在事务上下文中不可控且不安全
注意:db.createCollection() 本身不支持事务,但它可以带 validator 选项,这样后续事务中的写入会受 Schema 约束。
Schema 验证必须绑定到集合,而非 Model
Mongoose 的 Schema 是应用层结构描述,不影响 MongoDB 底层行为。真正起验证作用的是集合级的 $jsonSchema 规则,它由 db.createCollection() 或 collMod 命令写入。例如:
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email"],
properties: {
email: { bsonType: "string", pattern: "^.+@.+$" }
}
}
},
validationLevel: "strict",
validationAction: "error"
})
这个规则会在事务提交时生效。Mongoose 的 required、default 等只是预处理逻辑,无法替代数据库层验证。
事务中使用 mongoose.connection.collection() 而非 Model
即使集合已存在,也不能直接用 User.save() 这类 Model 方法进事务——它们绕过事务 session。必须显式获取原生 collection 实例:
- ✅ 正确:
const usersCol = mongoose.connection.collection("users"),再调用usersCol.insertOne(doc, { session }) - ❌ 错误:
new User(doc).save(),它不接受session参数,也不走事务通道
另外,Mongoose 的中间件(如 pre("save"))在事务中不会触发,因为底层没走 Model 流程。
最易被忽略的一点:复制集状态必须稳定。事务要求主节点可写、从节点同步延迟低于 10 秒,否则 session.commitTransaction() 可能卡住或回滚——这和集合是否存在无关,但会让问题排查误入歧途。


















