处理并发请求

问题描述 投票:0回答:1

我正在使用 NestJSPrisma ORMMySQL 在支付网关系统中工作。我在处理并发付款请求时遇到问题。当同时发出多个请求时,系统会从用户数据库中检索相同的可用余额,从而导致付款不正确。

问题: 每个请求都会从可用余额中扣除支付金额。 并发请求获取相同的余额值,导致最终用户余额存在差异。

我尝试过的: 在处理请求时使用 SELECT ... FOR UPDATE 查询锁定用户行。 Prisma 的 $transaction 包装了支付流程并确保原子性。

异步initiatePayout(有效负载:PayoutInitiateRequestDto,请求:IRequest):Promise { 返回等待 this.prisma.$transaction(async (prisma) => { // 锁定事务的用户行 const 用户 = 等待 prisma.$queryRaw

SELECT * FROM "User" WHERE "id" = ${userId} FOR UPDATE
;

if (!user) {
  throw new Error('User not found');
}

const availableBalance = user[0]?.totalPayout;
const payoutAmount = +payload.amount;

// Check if the available balance is sufficient
if (availableBalance < payoutAmount) {
  throw new Error('Insufficient balance');
}

// External API call for payout process
const apiResponse = await this.externalApi.payout(payload);

if (apiResponse.success) {
  // Deduct the balance after successful payout
  await this.user.findOneAndUpdate({
    { id: userId },
     { totalPayout: availableBalance - payoutAmount },
  });
}

return apiResponse;

}); }

mysql concurrency nestjs prisma
1个回答
0
投票

实施条件更新:

条件更新是一种常见的乐观方式,用于在并发访问时保持数据一致,即并发时的一致性。有关此类案例的更多信息,请参阅此处的问答:用户可以通过发起多次并发提款来同时提款超过钱包余额

注意:下面重构的代码可能在语法上有所不同,因为我遵循 mongoose 进行对象建模。然而,条件更新的逻辑保持不变,请对给定语句中的 prisma 进行必要的语法更正。

请重构以下代码:

if (apiResponse.success) {
  // Deduct the balance after successful payout
  await this.user.findOneAndUpdate({
    { id: userId },
     { totalPayout: availableBalance - payoutAmount },
  });
}

就像这样:

// performing a conditional update to safeguard
// the possible write-write conflict
if (apiResponse.success) {
  // Deduct the balance after successful payout
  const newDoc = await this.user.findOneAndUpdate({
    { id: userId, totalPayout: { $gte : availableBalance  } },
    { totalPayout: availableBalance - payoutAmount },
  });

 // informing user for the needful action
  if (newdoc) {
    console.log(`Updation passed`);
  } else {
    console.log(
      `Updation failed - write-write conflict detected`
    );
    // please provide the code to revert the payout transaction here.
  }
}

配备条件更新的重构代码会在更新时检查是否有足够的余额。如果有足够的余额,则可以安全地继续,否则,这意味着发生了竞争条件,其他一些用户会话已经使用了余额。 如果中止更新,必须相应地通知用户,并且已经发生的支付交易也必须恢复。

另请注意,如果有并发会话使用了一些余额,但仍有足够的余额用于当前交易,则可以安全地继续。因此,这种方法不会以悲观的方式工作,即使可能的并发事务也会被阻塞。

© www.soinside.com 2019 - 2024. All rights reserved.