MongoDB事务隔离问题:外部修改读取数据后事务是否自动终止?
MongoDB事务中外部修改读取数据的行为说明
- 默认情况下,你的事务不会自动终止。MongoDB事务默认采用快照隔离级别:事务启动时会生成一个数据快照,事务内所有读操作都基于这个快照执行,外部在事务期间对数据的写入修改,不会影响事务内的读结果,也不会触发事务自动中止。
- 回到你的代码示例:
find操作读取的是事务启动时的快照数据,即便外部修改了符合qty: {$gt:4}条件的文档,事务后续的update操作依然会正常执行,不会因为外部的写入操作而自动终止。 - 如果需要实现“读取的数据被外部修改则中止事务”的逻辑,需要手动实现乐观锁机制:
- 读取数据时,同时记录文档的版本标识(比如自定义的
version字段,或者MongoDB内置的更新时间戳) - 执行更新操作时,将版本标识作为更新条件的一部分
- 检查更新操作的返回结果,如果没有匹配到任何文档,说明数据已被外部修改,此时手动抛出错误终止事务
- 读取数据时,同时记录文档的版本标识(比如自定义的
手动实现乐观锁的示例代码:
await session.withTransaction(async () => { const coll1 = client.db('mydb1').collection('foo'); // 读取目标文档及版本号 const targetDoc = await coll1.findOne({ qty: { $gt: 4 } }, { session }); if (!targetDoc) return; const originalVersion = targetDoc.version; // 事务内的中间业务逻辑 // ... // 更新时校验版本,确保数据未被外部修改 const updateRes = await coll1.updateOne( { id: 3, version: originalVersion }, { $set: { qty: 2 }, $inc: { version: 1 } }, { session } ); // 无匹配文档则手动终止事务 if (updateRes.modifiedCount === 0) { throw new Error("数据已被外部修改,事务中止"); } }, transactionOptions);
内容的提问来源于stack exchange,提问作者Paulo
相关产品推荐
相关产品推荐

