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用户是否被修改。 这能工作吗?
您可以使用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的,这意味着查找和更新都将被执行,而不会有另一个操作干扰这些步骤。
文档摘录:
在修改单个文档时,
findAndModify
和update()
方法会自动更新文档。