MongoDB乐观并发结合upsert:单原子操作保存同ID最新序列号消息
原子Upsert实现方案
核心逻辑
MongoDB单文档写操作天然具备原子性,我们只需把「仅当新消息sequenceNumber更大才写入」的规则加入过滤条件,配合upsert参数,即可完全替代原有先查后写的逻辑,彻底避免多节点并发的竞态问题,同时性能更优。
原生MongoDB语法
db.your_collection.updateOne( // 过滤条件:匹配id,且现有文档的sequenceNumber小于新值 { "_id": newDoc.id, "sequenceNumber": { $lt: newDoc.sequenceNumber } }, // 写入完整新文档 { $set: { "sequenceNumber": newDoc.sequenceNumber, "data": newDoc.data // 其余字段按需补充 } }, { upsert: true } )
执行逻辑说明:
- 文档不存在时:过滤条件无匹配,触发upsert直接插入新文档
- 文档存在且现有sequenceNumber < 新值:过滤条件匹配,执行更新
- 文档存在且现有sequenceNumber >= 新值:过滤条件不匹配,不执行任何操作
.NET 实现代码
// 定义过滤条件 var filter = Builders<YourDocumentClass>.Filter.And( Builders<YourDocumentClass>.Filter.Eq(doc => doc.Id, document.Id), Builders<YourDocumentClass>.Filter.Lt(doc => doc.SequenceNumber, document.SequenceNumber) ); // 执行原子替换+upsert await _collection.ReplaceOneAsync( filter: filter, replacement: document, options: new ReplaceOptions { IsUpsert = true } );
优势
- 全程原子操作,无并发竞态问题,完全适配多节点部署场景
- 减少一次数据库查询交互,吞吐量更高,应对每秒数百条消息毫无压力
- 代码更简洁,无需处理查询后的分支判断逻辑
内容的提问来源于stack exchange,提问作者Michael D.
相关产品推荐
相关产品推荐

