2

将 NodeJS 与 MongoDB+Mongoose 一起使用。

首先,我知道异步非阻塞代码的优点。所以我确实处理回调。但最后我遇到了以下问题。

假设我有一个用户可以随时调用的函数。而且有可能,一个超级“闪电般”的用户几乎同时调用了两次。

function do_something_with_user(user_id){
    User.findOne({_id:user_id}).exec(function(err,user){ // FIND QUERY
        // Do a lot of different stuff with user
        // I just cannot update user with a single query
        // I might need here to execute any other MongoDB queries
        // So this code is a set of queries-callbacks
        user.save() // SAVE QUERY
    })
}

当然它是这样执行的:FIND QUERY, FIND QUERY, SAVE QUERY, SAVE QUERY

这完全打破了应用程序的逻辑(应该查找查询、保存查询、查找查询、保存查询)。所以我决定通过为特定用户“锁定”整个函数来防止异步行为(所以函数代码内部仍然是异步的)。

var lock_function_for_user = {}

function do_something_with_user(user_id){
    if(!lock_function_for_user[user_id]){
        lock_function_for_user[user_id] = true
        User.findOne({_id:user_id}).exec(function(err,user){
            // Same code as above
            user.save(function(){
                lock_function_for_user[user_id] = false
            })
        })
    } else {
        setTimeout(function(){
            do_something_with_user(user_id)
        },100) // assuming that average function execution time is 100ms in average
    }
}

所以,我的问题是:这是一个好的做法,好的 hack 还是坏的 hack?如果这是一个糟糕的黑客,请提供任何其他解决方案。特别是,当我们扩展和启动多个 NodeJS 进程时,我怀疑这个解决方案是否会起作用。

4

2 回答 2

2

这是一种非常糟糕的做法,您永远不应该使用计时器来控制代码流。

这里的问题称为原子性。如果你需要做 find-save,find-save 那么你需要以某种方式打包这些操作(事务)。这取决于您使用的软件。在 redis 中,您有 multi 和 exec 命令。在 mongodb 中有 findAndModify()。另一种解决方案是使用索引。当您尝试两次保存同一字段时,您会收到错误消息。在 mongoose 的 schemaType 中使用属性“index: true”和“unique: true”:

var schema = mongoose.Schema ({
    myField: { type: String, index: true, unique: true, required: true },
});

这就是您需要的:Mongodb - 隔离操作序列 - 执行两阶段提交。但要考虑到,如果您需要进行大量事务,mongodb 可能不是最佳选择。

于 2013-03-28T23:23:52.050 回答
0

你不想浪费内存,所以更换

lock_function_for_user[user_id] = false

delete lock_function_for_user[user_id]

除此之外:如果发生冲突,您可以保持乐观并重试。只需忽略锁定并确保数据库在出现问题时注意到(并在这种情况下重试)。当然,哪种方式更好取决于这种冲突真正发生的频率。

于 2013-03-28T23:22:41.737 回答