在 NestJS 中安全处理并发产品订单和数量更新

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

我目前在 NestJS 应用程序中面临与管理并发产品订单和数量更新相关的挑战。以下是我用来创建订单的代码的简化版本:

async createOrder(userId: string, products: ProductForOrder[], paymentStatus: PaymentStatusEnum): Promise<OrdersRo> {
    for (const product of products) {
      const foundProduct = await this.productsRepository.findOne({
        where: { id: product.productId },
      });
      if (!foundProduct) {
        throw new HttpException("Product's ID not found", HttpStatus.NOT_FOUND);
      }
      if (foundProduct.unitsOnStock - product.quantity < 0) {
        throw new HttpException(
          `Insufficient stock for product: ${foundProduct.name}`,
          HttpStatus.BAD_REQUEST,
        );
      }
    }

    const user = await this.usersRepository.findOne({ where: { id: userId } });
    if (!user)
      throw new HttpException("Invalid user's ID", HttpStatus.NOT_FOUND);

    const order = await this.ordersRepository.create({ customer: user, paymentStatus });
    await this.ordersRepository.save(order);

    for (const product of products) {
      const foundProduct = await this.productsRepository.findOne({
        where: { id: product.productId },
      });
      await this.productsRepository.update(foundProduct.id, {
        unitsOnStock: foundProduct.unitsOnStock - product.quantity,
      });

      const orderDetails = await this.orderDetailsRepository.create({
        product: foundProduct,
        order,
        quantity: product.quantity,
      });

      await this.orderDetailsRepository.save(orderDetails);
    }
    return this.toResponseOrder(order);
  }

在此代码中,我在创建订单之前根据库存可用数量检查产品的可用性。但是,当多个用户尝试同时为同一产品下订单时,我担心潜在的并发问题。由于可用性检查和实际订单创建之间存在时间差距,可用数量可能会过时。

我想寻求有关如何有效处理这种情况的建议。我可以采用哪些策略或方法来确保自动执行产品可用性检查和数量更新,从而防止同时下达多个订单时出现任何冲突和不一致?我们将非常感谢您的指导和见解。预先感谢您的帮助!

concurrency transactions nestjs locking typeorm
1个回答
0
投票

对于从库存中读取可用数量,您可以尝试使用 setLocking('pessimistic_write') 进行读取查询,以确保在创建订单之前数量不会被更改:

stocks = await queryRunner.manager
          .getRepository(Stock)
          .createQueryBuilder("stock")
          .useTransaction(true)
          .setLock("pessimistic_write")
          .where("stock.productId = :id", { id: id })
          .getMany();
© www.soinside.com 2019 - 2024. All rights reserved.