使用樂觀鎖解決超賣問題的代碼實現

問題:下單成功的條件是什麼?
結果:首先庫存大於購買量,然後更新庫存和銷量時原始庫存沒變。
結論:所以在用戶庫存滿足的情況下,如果更新庫存和銷量時原始庫存有變,那麼繼續給用戶下單的機會。

實現代碼

# 2, 訂單提交
class OrderCommitView(MyLoginRequiredMixin):
    @transaction.atomic
    def post(self, request):
        # 1,獲取參數
        dict_data = json.loads(request.body.decode())
        address_id = dict_data.get("address_id")
        pay_method = dict_data.get("pay_method")

        # 2,校驗參數
        # 2,1 爲空校驗
        if not all([address_id, pay_method]):
            return http.JsonResponse({"code": RETCODE.NODATAERR, "errmsg": "參數不全"})

        # 2,2 地址是否存在
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({"code": RETCODE.NODATAERR, "errmsg": "地址不存在"})

        # 2,3 支付方式校驗
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM["CASH"], OrderInfo.PAY_METHODS_ENUM["ALIPAY"]]:
            return http.JsonResponse({"code": RETCODE.NODATAERR, "errmsg": "支付方式有誤"})

        # 3,數據入庫
        # 3,1 訂單編號
        user = request.user
        order_id = timezone.now().strftime("%Y%m%d%H%M%S") + "%09d%s" % (random.randint(0, 999999999), user.id)

        # 3,2 訂單狀態
        if pay_method == OrderInfo.PAY_METHODS_ENUM["CASH"]:
            status = OrderInfo.ORDER_STATUS_ENUM["UNPAID"]
        else:
            status = OrderInfo.ORDER_STATUS_ENUM["UNSEND"]

        # TODO 設置保存點
        sid = transaction.savepoint()

        order_info = OrderInfo.objects.create(
            order_id=order_id,
            user=request.user,
            address=address,
            total_count=0,
            total_amount=Decimal(0.0),
            freight=Decimal(10.0),
            pay_method=pay_method,
            status=status
        )

        # 3,3 獲取redis中需要結算的商品
        redis_conn = get_redis_connection("carts")
        cart_dict = redis_conn.hgetall("carts_%s" % user.id)
        selected_list = redis_conn.smembers("selected_%s" % user.id)

        # 4 遍歷,創建訂單商品數據
        for sku_id in selected_list:
            # 4.1 獲取sku對象,數量
            sku = SKU.objects.get(id=sku_id)
            count = int(cart_dict[sku_id])

            # 4,2 判斷庫存是否充足
            if count > sku.stock:
                transaction.savepoint_rollback(sid)  # TODO 回滾
                return http.JsonResponse({"code": RETCODE.NODATAERR, "errmsg": "庫存不足"})

            # 4,3 減少庫存,增加銷量
            sku.stock -= count
            sku.sales += count
            sku.save()

            # 4,4 創建訂單商品對象
            OrderGoods.objects.create(
                order=order_info,
                sku=sku,
                count=count,
                price=sku.price
            )

            # 4,5 累加數量,和價格到訂單信息表
            order_info.total_count += count
            order_info.total_amount += int(count * sku.price)

        # 5,保存訂單信息表
        order_info.save()
        transaction.savepoint_commit(sid)  # TODO 提交

        # 6,清空redis
        redis_conn.hdel("carts_%s" % user.id, *selected_list)
        redis_conn.srem("selected_%s" % user.id, *selected_list)

        # 7,返回響應
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "下單成功"})
發佈了56 篇原創文章 · 獲贊 73 · 訪問量 2876
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章