lockingMongo和Nodejs

我正在尝试构build一个非常简单的购物应用程序,用户可以通过虚拟货币购买物品。

我正在使用多个NodeJS进程,所以我很害怕asynchronous的一部分。

这就是我所做的:

app.post('/buy', function(req, res){ User.findOne({_id: req.userId}, function(err, user){ if(user.balance >= ITEM_PRICE){ User.decrementBalance({_id: req.userId}, function(err){ //Do transaction, give item to user, etc }); } else { //Not enough money } }); }); 

这种方法的问题是用户可以在很短的时间内提交多个/购买请求。 这可能会导致竞争状态,第二个请求在第一个请求减less之前检查用户的余额。 这导致用户具有负值,并且取得比他的余额更多的物品。

有没有办法解决这个问题? 我正在考虑做一个User.update()并validation用户是否被修改。 这能工作吗?

       

网上收集的解决方案 "lockingMongo和Nodejs"

您可以使用Model.findOneAndUpdate() ,它将在一个primefaces操作中结合查询余额调整:

 User.findOneAndUpdate({ _id : req.userId, balance : { $gte : ITEM_PRICE } }, { $inc : { balance : -ITEM_PRICE } // there is no $dec }, { new : true }, function(err, user) { ... }); 

如果查询条件失败(或者没有用户使用该ID,或者没有足够的余额),则user将为null (或undefined ,不确定)。 由于它看起来像只处理login用户,ID可能永远是有效的,所以如果user没有定义,这将意味着他们的平衡不够高。

由于new : true ,如果用户文档被返回,它将反映新的余额(默认情况下,它会返回旧的文档)。

编辑 :一些更多的澄清:你是正确的评估,执行.findOne和发布更新(这是什么User.decrementBalance()将执行)之间的竞争条件。

然而, findOneAndUpdate是特殊的,因为它将使用特定的MongoDB命令( findAndModify ),它保证是primefaces的,这意味着查找和更新都将被执行,而不会有另一个操作干扰这些步骤。

文档摘录:

在修改单个文档时, findAndModifyupdate()方法会自动更新文档。