Node.js原子性操作MongoDB

假设基础数据为:


{
    "name" : "cb",
    "data" : 0,
}

有时候为了充分利用多核,会同时开启多个node进程,但是若部分代码若涉及到操作mongodb就会有下面现象.
“理想情况下”,多个进程执行完后得数据为:


{
    "name" : "cb",
    "data" : 6000,
}

其实不然 !

我们看看获得结果是怎么样的.


co(function* () {
    for (var i=0; i< 3000; i++) {
        var getTest = yield mongoCtest.findOne({"name":"cb"}, {"fields":{"_id":0}});
        getTest.data =  getTest.data+1;
        console.log(getTest);
        yield mongoCtest.update({"name":"good"}, {"$set":getTest});
    }
})();

上面的程序同时开两个,多个进程同时操作一个数据.
可能结果会是:
多进程操作Mongo

我们知道Mongo是不支持事务的,如果你能容忍上面的弱一致性,那么没问题.但是如果你不能容忍,要么考虑MySql关系型数据库,要么自己解决事务问题.

下面我来说下基于Mongo怎么解决事务问题.
我们需要对每个数据加一个version来控制.直接上代码:


co(function* () {
    for (var i=0; i< 3000; i++) {
        while (1) {
            var getTest = yield mongoCtest.findOne({"name":"cb"}, {"fields":{"_id":0}});
            getTest.data =  getTest.data+1;
            var originalVer = getTest.ver;
            getTest.ver = getTest.ver+1;
            console.log(getTest);
            var ret = yield mongoCtest.update({"name":"cb", "ver":originalVer}, {"$set":getTest});
            if (ret)  break;
        }
    }
})();

下面就是我们想要的结果:)

原子性控制