• 乐观锁实现电商网站秒杀


    
    
    from django_redis import get_redis_connection


    class
    OrderCommitView(view):
      @transaction.atomic
      def post(self, request):
        # 判断用户是否登录
        user = request.user
        if not user.is_authenticated():
          return JsonResponse("res":0,"error_msg":"用户未登录"
    )
        
        addr_id = request.POST.get('addr_id')
        pay_method = request.POST.get('pay_methon')
        sku_ids = request.POST.get('sku_ids')
        
        if not all([addr_id, pay_method, sku_ids]):
          return JsonResponse({'res':1, 'error_msg':'params not enough'})

        # 校验支付方式
        if pay_method not in OrderInfo.PAY_METHODS.keys():
          return JsonResponse('ret':2,'error_msg':'非法支付方式')

        # 校验地址
        try:
          addr = Address.objects.get(id=addr_id)
        except Address.DoesNotExist:
          return JsonResponse('ret':3,'error_msg':"地址非法")

        # 创建订单核心业务
        订单id :日期加用户的id
        order_id = datetime.now().strftime("%Y%m%d%H%M%S")+str(user.id)

        # 运费
        transit_price = 10

        # 总数目总金额
        total_count = 0
        total_price = 0
        
        # 设置事物保存点
        save_id = transaction.savepoint()
        try:
          # todo 向df_oeder_info表中添加一条记录
          order = OrderInfo.objects.create(order_id=order,user=user,pay_method=pay_method,total_count=total_count,total_price=total_price)
          conn = get_redis_connection('default')
          cart_key = 'cart_%d'%user.id
          sku_ids = sku_ids.split(',')
          for sku_id in sku_ids:
            # 获取商品信息
            # for 循环3次 尝试都能下单成功
            for i in range(3):
              try:
                sku = GoodsSKU.objects.get(id=sku_id)
              except:
                # 商品不存在
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'ret':4,'error_msg':"商品不存在"})
            

              # 从redis中获取用户需要购买的商品的数量
              count = conn.hget(cart_key,sku.stock)
              # todo 判断商品的库存
              if int(count) > sku.stock:
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'res':6,'error_msg':'商品库存不足'})
              # todo 更新商品的库存和销量
              origin_stock = sku.stock
              new_stock = origin_stock - int(count)
              new_sales = sku.sales + int(count)
            
                   print('user:%s,stock:%s'%(user.id,sku.stock))
              import time
              time.sleep(10)

      # upload df_goods_sku set stock=new_stock,sales=new_sales where id=sku_id and stock=origin_stock
       #乐观锁 res返回受影响的行数
              res = GoodsSKU.objects.filter(id=sku_id,stock=origin_stock).update(stock=new_stock.sales=new_sales)
              if res == 0:
                if i ==2:
                  transactin.savepoint_rollback(save_id)
                  return JsonResponse({'res':7,'error_msg':"下单失败2})
                continue
              # todo 向df_order_goods表中添加一条记录
              OrderGoods.objects.create(order=order,
                           sku=sku,count=count,price=sku.price)
              # todo 累加计算订单商品的总数量和总价格
              amount = sku.price*int(count)
              total_count += int(count)
              total_price += amount
              break
          # todo更新订单信息表中的商品的总数量和总价格
          order.total_count = total_count
          order.total_price = total_price
          order.save()
        except Exception as e:
          transaction.savepoint_rollback(save_id)
          return JsonResponse('res':7,'error_msg':'下单失败')
        # 提交事务
        transaction.savepoint_commit(save_id)
        # 提交事务
        conn.hdel(cart_key,*sku_ids)

        # 返回应答
        return JsonResponse({'res':5,'message':'创建成功'})


    最后一步:

    乐观锁需要将数据库(MYSQL)的默认隔离程度可重复读(读的是第一次读到的数据),所以需要将MySQL的隔离级别更改为读已提交
    打开MySQL的配置文件 sudo vi /etc/mysql/mysqlconf.d/
    修改为读已提交
    transaction_isolation = READ_COMMITTED
    重启MySQL:sudo service mysql restart
  • 相关阅读:
    值得学习的东西
    【单调队列】转载
    dom基础3 — 简易版template.js
    js基础6 — 数组对象
    js基础6 — 字符串基本操作
    js基础5 — 将十六进制颜色转为rgba()
    js基础4 — 数组操作
    placeholer属性修改
    clipboard.js实现复制到剪切板
    JS 获取指定日期在当年的第几周
  • 原文地址:https://www.cnblogs.com/tangda/p/12348174.html
Copyright © 2020-2023  润新知