Node.js 如何同时处理多个购买请求

Node.js 如何同时处理多个购买请求,node.js,database,Node.js,Database,让我们想象一下,我们有一个购物网站,用户可以使用其帐户余额购买物品 用户A请求购买项目B 以下是步骤: 数据库获取用户的余额 检查余额是否超过成本 更新用户余额(balance-cost=newBalance) 现在我的问题从这里开始: 由于javascript是单线程的,我们以异步方式请求db,如果: 用户A发送多个购买项目的请求 另一个用户尝试购买该项目(购买1次后,该项目应缺货) 我已经做了一些测试,我想知道什么是防止userA购买多个物品的最佳方法,而实际上他在第二次购买后应该失

让我们想象一下,我们有一个购物网站,用户可以使用其帐户余额购买物品

用户A请求购买项目B

以下是步骤:

  • 数据库获取用户的余额
  • 检查余额是否超过成本
  • 更新用户余额(
    balance-cost=newBalance
现在我的问题从这里开始:

由于javascript是单线程的,我们以异步方式请求db,如果:

  • 用户A发送多个购买项目的请求

  • 另一个用户尝试购买该项目(购买1次后,该项目应缺货)

我已经做了一些测试,我想知道什么是防止userA购买多个物品的最佳方法,而实际上他在第二次购买后应该失去平衡

我的测试:

const fs=require('fs');
施工成本=500;
//.data.txt的内容为“1000”
函数getMoneyFromDatabase(){
返回新承诺((解决、拒绝)=>{
fs.readFile('./data.txt',utf-8',(错误,数据)=>{
如果(错误)拒绝(错误);
else解析(数字(数据));
});
});
}
函数setMoneyToDatabase(newMoney){
返回新承诺((解决、拒绝)=>{
fs.writeFile('./data.txt',newMoney,(err)=>{
如果(错误)拒绝(错误);
else解析();
});
});
}
异步函数getMoney(){
const money=等待getMoneyFromDatabase();
如果(钱>=成本){
//能够购买
console.log(“能够购买”);
const newMoney=货币-成本;
等待setMoneyToDatabase(新币);
console.log(“已购买”);
}
}
获得金钱();
获得金钱();
获得金钱();
获得金钱();
它记录了4次购买的
,而实际上它只能购买两次
保存在
data.txt
中的数据是500,而它应该是-1000(500,0,-500,-1000)

您可以做的一件事是确保与收费相关的API请求是幂等的,这意味着它们可以发送多次,但只要请求相同,就会产生相同的结果

您可以通过将唯一密钥与请求一起发送来实现幂等请求,以确保只有第一次将其作为新请求接受,否则将作为重复请求处理。当您希望安全地重试请求而不意外地多次向用户收费时,这也很有用

许多支付处理程序对此具有内置支持,例如:

至于库存,您应该只在验证付款或如果不是自动付款时,才减少库存,因为第一个用户有待处理的发票。否则,即使用户有余额,但无法处理付款,股票也会下跌


实施支付很难,只有经过反复试验后才能学会以体面的方式实施,我建议您尝试使用最小的应用程序,通过处理边缘案例,使用支付网关(如Stripe和advance)处理支付。

这就是您需要在数据库中进行原子操作的地方。请求平衡、检查平衡,然后将其设置为两个不同的数据库操作,这是一个竞争条件。这不是原子性的,可能会导致其他请求的竞争条件问题。您需要在数据库中执行一个原子操作,使总数递减,或者在余额不足时返回一个错误。或者,在某些数据库中,使用锁。如何在任何给定的数据库中实现这一点是特定于该数据库的,但由于这是一个常见的数据库问题,它应该具有这样的功能。