Ste*_*Gee 3 mongoose mongodb node.js express
我正在尝试构建一个非常简单的购物应用程序,用户可以在其中使用虚拟货币购买商品。
我为此使用了多个NodeJS进程,因此我担心事情的异步部分。
这是我的工作:
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
}
});
});
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于,用户可以在很短的时间内提交多个购买请求。这可能会导致出现争用情况,在这种情况下,第二个请求会在第一个请求减少余额之前检查用户的余额。这导致用户具有负值,并且拿出比其余额所允许的更多的物品。
有办法解决吗?我正在考虑做一个User.update()并验证用户是否被修改。那行得通吗?
您可以使用Model.findOneAndUpdate()它,它将查询和余额调整合并在一个原子操作中:
User.findOneAndUpdate({
_id : req.userId,
balance : { $gte : ITEM_PRICE }
}, {
$inc : { balance : -ITEM_PRICE } // there is no $dec
}, {
new : true
}, function(err, user) {
...
});
Run Code Online (Sandbox Code Playgroud)
如果查询条件失败(没有用户使用该ID,或者他们没有足够的余额),user将为null(或undefined,不确定)。由于您似乎只在与登录用户打交道,因此该ID可能始终有效,因此,如果user未定义ID,则意味着他们的余额不够高。
由于存在new : true,如果返回了用户文档,它将反映新的余额(默认情况下,它将返回旧文档)。
编辑:需要更多说明:在执行.findOne和发布更新之间(这是User.decrementBalance()将要执行的操作)之间存在竞争条件的评估是正确的。
但是,findOneAndUpdate它的特殊之处在于它将使用特定的MongoDB命令(findAndModify),该命令保证是原子的,这意味着将执行查找和更新操作,而不会在这些步骤之间干扰其他操作。
文档摘录:
修改单个文档时,两者
findAndModify和update()方法都会自动更新文档。
| 归档时间: |
|
| 查看次数: |
1298 次 |
| 最近记录: |