Meteor:服务器端的Meteor.collections会发生竞争吗?

时间:2013-08-02 00:46:49

标签: javascript mongodb meteor race-condition

在我的server / server.js

Meteor.methods({
    saveOnServer: function() {
        var totalCount = Collections.find({
            "some": "condition"
        }).count();
        if (totalCount) {
            var customerId = Collections.update('someId', {
                "$addToSet": {
                    objects: object
                }
            }, function(err) {
                if (err) {
                    throw err;
                } else {
                    return true;
                }
            });
        } else {}
    }
});

我担心当2个客户端同时调用saveOnServer()时,它会为每个客户端返回相同的totalCount,并且最终会在对象id中插入相同的整数。最终目标是在服务器端使用原子操作插入行,该操作仅在成功返回totalCount并且插入文档以确保不存在重复ID时才完成?我试图不使用mongodb _id但是有我自己的整数递增id列。

我想知道如何确保每个插入操作的字段都会自动递增?我目前依赖于获取文件总数。这里有竞争条件吗?如果是这样,处理这个问题的流星方式是什么?

3 个答案:

答案 0 :(得分:9)

在Meteor的并发模型中,您可以将整个方法想象为不间断的事件块。为了让Meteor从中途运行一个方法转换为开始另一个方法,你需要“屈服” - 方法需要发出信号,“我可以被打断。”

方法在异步执行某些操作时会产生,实际上这意味着您在Meteor 0.6.5及更高版本中执行数据库更新或调用带回调的方法。由于您为update电话提供了回叫,Meteor将始终尝试在调用updateupdate的回调之间执行某些操作。但是,在Meteor 0.6.4.2及更早版本中,无论使用何种回调,数据库更新都是不可中断的。

但是,对saveOnServer的多次调用将按顺序发生,并且不会导致竞争条件。您可以调用this.unblock()以允许多次调用saveOnServer同时发生 - 即,不共享同一个标记为saveOnServer queue的队列的不间断事件块。

根据您拥有的代码,修改Collections的另一种方法可以在调用和更新之间更改count()的值。

您可以通过实施以下数据模型来阻止一种方法在中途使另一种方法无效:

saveOnServer : function () {
// ...
  Collections.update({_id:someId, initialized:true, collectionCount: {$gt: 0}},
    {$addToSet: {objects: object}});
///...
}

Collections添加对象时:

insertObject: function() {
//...
  var count = Collections.find({some: condition}).count();
  Collections.insert({_id:someId, initialized:false, collectionCount: count});
  Collections.update({initialized:false},
    {$set:{initialized:true}, $inc: {collectionCount: 1}});
}

请注意,虽然这看起来效率低下,但它反映了进行更新的确切成本,并且在不同方法中插入的行为与您的预期方式相同。在saveOnServer中,您无法插入。

相反,如果你从Collections.update删除回调,它将同步发生,并且不会有比赛条件Meteor 0.6.5及更高版本。

答案 1 :(得分:1)

您可以使此集合在索引字段上具有唯一键,然后按如下所示更新它:

1)每当您插入集合时,首先执行查询以获取最大索引并插入索引为+ 1的文档。

2)要找出文档的数量,只需执行查询即可获得索引的最大值。

插入现在是一对查询,即读取和写入,因此它可能会失败。 (但是,DB操作总是会失败。)但是,它永远不会使数据库处于不一致状态 - Mongo索引将保证这一点。

在Meteor中构建索引的语法是:

MyCollection._ensureIndex('index', {unique: 1});

答案 2 :(得分:1)

另一种方法是从hibernate / jpa的机制开始 - 也就是设置一个碰撞字段。大多数情况下,这可以是在每次更新时设置的更新时间戳。在进行任何更新之前,请查询更新时间戳。然后,您可以指定更新时间戳是您刚刚获取的更新。如果它在过渡期间发生了变化,则更新不会发生 - 并且您检查行更新与否的返回代码/计数。 当您为此碰撞字段添加注释时,JPA会自动为您执行此操作 - 但这基本上就是它在幕后的作用