并发处理 Django乐观锁的实现

商品超卖问题:多个用户同时下单同一个商品时,可能会出现资源竞争问题,导致库存结果出现异常

乐观锁解决:

乐观锁并不是真正的锁,只是更新数据的时候多加一层判断

更新的时候判断此时库存是否和之前查询的库存一样,如果一样则表示没人修改,可以进行更新;否则表示有人抢过该资源,不再进行更新。类似下面操作:

update tb_sku set stock=2 where id=1 and stock=7;

SKU.objects.filter(id=1, stock=7).update(stock=2)

思路:

创建保存点

查询库存

更新库存时,将之前查询的库存和商品id一起作为更新的条件

当受影响行为0表示更新失败,回滚到保存点(没有操作数据库的时候)

重新查询,重复到n次不成功返回错误 (这里while True 直到库存为0停止)

示例:

from django.db import transaction

# 部分代码使用事物
with transaction.atomic():
    # 创建保存点
    save_id = transaction.savepoint()
    try:
        # 生成订单信息
        order = OrderInfo.objects.create(
            ...
        )
        # 从redis取购物车要结算的商品数据(省略写法)
        ...
        cart = {shu.id: sku_count, ...}
        
        while True: # 直到没有库存为止
            sku = SKU.objects.get(pk=sku_id)  # 不加锁查询
            # 购物车商品数量
            count = cart[shu.id]
            # 获取原始库存
            origin_stock = sku.stock
            # 判断商品库存是否充足
            if origin_stock < count:
                # 库存不足
                raise serializers.ValidationError('库存不足')
            
            # 演示并发请求
            import time
            time.sleep(5)

            # 记录原来的值
            origin_sales = sku.sales
            # 计算要更新的值
            new_stock = origin_stock - count
            new_sales = origin_sales + count

            # 返回受影响的行数
            ret = SKU.objects.filter(id=sku.id,stock=origin_stock).update(stock=new_stock,sales=new_sales)
            if ret == 0:
                # 更新成功,进入下次循环重新判断
                continue
            else:
                # 保存订单商品数据
                ...
                
                # 更新成功,退出while循环
                break    
            
            ...
            
    except Exception as e:
        # 提交保存点
        transaction.savepoint_rollback(save_id)
        raise serializers.ValidationError('下单失败')
    # 提交事务
    transaction.savepoint_commit(save_id)
    # 清除购物车中已经结算的商品
    ...
    return order
发布了52 篇原创文章 · 获赞 34 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43789195/article/details/100736343