两个客户端之间的数据同步(验证)

时间:2019-10-28 09:12:38

标签: c# asp.net-core async-await aspnetboilerplate abp

我有一个基于ASP.NET Boilerplate(Angular前端和MSSQL数据库)构建的网上商店。
网上商店中有物品,我想保留这些物品的清单。 每次创建订单时,库存都会更新。所以基本上我有一个包含网上商店,商品和订单的数据库。
我有这些对象的存储库和管理器。

一切正常,但是当两个客户端同时加载网上商店时,就会出现此问题。

Client1打开网页:

  • 网上商店1
    • 第1项:“有10个可用项”
    • 第2项:“有8个可用项”

Client2同时打开网页:

  • 网上商店1
    • 第1项:“有10个可用项”
    • 第2项:“有8个可用项”

第一个购买所有可用商品的人应该能够创建订单,第二个应该出错。

创建订单后,后端将检查是否有足够的可用物品。 但是,当在第一个客户的订单创建之前加载了网上商店时,第二个客户不知道更新的库存,因此也可以创建订单。
意思是Item1可以卖出20件!

如何在后端的两个会话之间“同步”数据?加载Webshop时似乎以某种方式将数据缓存在后端中。

CreateOrder函数

public async Task<CreateOrderResponseDto> Create(CreateOrderDto input, long? userId)
{
    input.OrderItems.ForEach(async o =>
    {
        if (!(await _salesItemManager.ReserveStock(o.SalesItemId, o.Quantity)).IsSuccess)
        {
            throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
        }
    });


    var salesPage = await _salesPageManager.Get(input.SalesPageId, false);

    if (salesPage.GetState() != StatePage.Published)
    {
        throw CodeException.ToAbpValidationException("Order", "PageNotAvailable");
    }

    if (salesPage.CommentsRequired.HasValue && salesPage.CommentsRequired.Value)
    {
        if (string.IsNullOrWhiteSpace(input.Description))
        {
            throw CodeException.ToAbpValidationException("Order", "CommentsRequired");
        }
    }

    var order = new Order
    {
        Address = input.Address,
        City = input.City,
        LastName = input.LastName,
        Name = input.Name,
        PostalCode = input.PostalCode,
        Email = input.Email,
        PhoneNumber = input.PhoneNumber,
        Description = input.Description,
        SalesPage = salesPage
    };


    try
    {
        order.Price = await _salesItemManager.GetPriceByOrders(input.OrderItems);
        order = await _orderRepository.InsertAsync(order);

        input.OrderItems.ForEach(async o =>
        {
            var orderItem = new OrderItem();
            orderItem.SalesItemId = o.SalesItemId;
            orderItem.OrderId = order.Id;
            orderItem.Quantity = o.Quantity;

            await _orderItemRepository.InsertAsync(orderItem);
        });

        if (input.SelectedSalesPageOptionId.HasValue)
        {
            order.SalesOption = await _salesPageManager.GetOption(input.SelectedSalesPageOptionId.Value);
        }

    }
    catch (Exception e)
    {
        throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
    }

    if (userId.HasValue && salesPage.User.Id == userId.Value)
    {
        var payment = await _paymentManager.CreateManualPayment(order, input.IsPaid);
        order.Payment = payment;

        return new CreateOrderResponseDto() { IsSuccess = true, PaymentUrl = string.Empty, OrderId = order.Id.ToString() };
    }
    else
    {
        var payment = await _paymentManager.CreatePayment(order);
        order.Payment = payment;
        return new CreateOrderResponseDto() { IsSuccess = true, PaymentUrl = payment.PaymentUrl, OrderId = order.Id.ToString() };
    }
}

ReserveStock函数

public async Task<GeneralDto> ReserveStock(Guid itemId, int quantity)
{
    var salesItem = await _salesItemRepository.GetAsync(itemId);

    if (salesItem == null || salesItem.Stock == null || salesItem.ReservedStock == null)
        return new GeneralDto() { IsSuccess = false };

    if (salesItem.Stock < quantity)
    {
        return new GeneralDto() { IsSuccess = false };
    }

    salesItem.Stock -= quantity;
    salesItem.ReservedStock += quantity;

    try
    {
        await _salesItemRepository.UpdateAsync(salesItem);
    }
    catch (Exception e)
    {
        throw CodeException.ToAbpValidationException("SalesItem", "SalesItemUpdate");
    }

    return new GeneralDto() { IsSuccess = true };
}

1 个答案:

答案 0 :(得分:1)

问题不是数据被缓存了。

问题是您的ReserveStock检查是调用者未等待的异步任务:

input.OrderItems.ForEach(async o =>
{
    if (!(await _salesItemManager.ReserveStock(o.SalesItemId, o.Quantity)).IsSuccess)
    {
        throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
    }
});

将异步ReserveStock检查分配给调用方正在等待的一系列任务:

var reserveStockChecks = input.OrderItems.Select(async o =>
{
    if (!(await _salesItemManager.ReserveStock(o.SalesItemId, o.Quantity)).IsSuccess)
    {
        throw CodeException.ToAbpValidationException("OrderItem", "OrderItemCreate");
    }
}).ToArray();

await Task.WhenAll(reserveStockChecks);