[提问] Nodejs里如何避免 mongodb 的脏读?

[提问] Nodejs里如何避免 mongodb 的脏读?

mongo 的 api 都是回调的方式,我每次从库里查出符合条件的记录,然后在回调函数中将这几条记录 update 掉状态,让他们不会再其他请求中被查找出来,相当于被消费掉了。

虽然还没遇到脏读的情况,但是我心里觉得是有隐患的。因为查找和更新不是一个事务里,而 node 处理事件的方式又是可以并发的,所以我担心并发的情况下,会造成 mongodb 脏读,多次消费同一个记录。

有没有好的解决方法?比如类似于 Critical Section 的方案,让竞争资源的代码不可以同时运行?


12 回复

mongo 自己是没有事物的。

你要用类似 async 来控制并发,让你这些访问数据库的操作顺序执行。


async 确实可以控制并发,但是我用的 mongojs 的 api 对于库的操作,还是异步的。。
所以即使控制了并发请求,让其串行处理,还是不能解决问题。

用 findAndModify .设个状态字段, undo,doing,done,

那只能模拟 MVVC 了

其实我也想用这个 findAndModify ……
但是因为要随机取,所以用的是 aggregate + $sample 管道。貌似 aggregate 里没有同时修改的方法。

  1. 换 mysql ,用悲观锁
    2. 用 CAS 机制自己做乐观锁

async 不是解决办法,集群不照样有问题

用集群,由 master 做锁调度

不需要同时修改吧, findAndModify 时候如果已经被消费了就不会产生任何效果。

查找到数据后, update 时带上查找条件,比如
collection.update({_id:123,proc:{$exists:false}},{$set:{proc:1}})
然后看返回的 modified 数量是不是 1 ,不是就不要处理。

不过一般还得考虑处理超时后别的进程接手的情况呢。

在Node.js中操作MongoDB时,避免脏读(Dirty Read)的关键在于确保你读取的数据是一致的和最新的。MongoDB主要通过读写关注和会话(Session)机制来实现这一点。

使用读写关注(Read Concern 和 Write Concern)

MongoDB提供了多种读写关注级别来控制数据一致性。

  • Read Concern:指定读取数据时所需的一致性级别。
  • Write Concern:指定写入数据时所需的确认级别。

在Node.js中使用mongodb官方驱动时,可以这样设置:

const { MongoClient } = require('mongodb');

async function main() {
    const uri = "your_mongodb_uri";
    const client = new MongoClient(uri, {
        readConcern: 'local', // 或 'majority' 以增强一致性
        writeConcern: 'majority' // 确保写入到大多数副本集成员
    });

    await client.connect();
    const db = client.db('your_database');
    const collection = db.collection('your_collection');

    // 读取操作
    const documents = await collection.find({}).toArray();
    console.log(documents);

    await client.close();
}

main().catch(console.error);

使用会话(Session)

对于更细粒度的控制,可以使用会话来确保读取操作在同一个会话中看到所有之前的写入操作:

const session = client.startSession();
const options = { session, readConcern: 'majority' };
const documents = await collection.find({}, options).toArray();

通过正确设置读写关注和会话,可以有效避免MongoDB中的脏读问题。

回到顶部