zoukankan      html  css  js  c++  java
  • 商品分类-商品详情-数据库脏读-不可重复读-幻读-订单生成

    商品详情的无限极分类

      --北京
    
        --朝阳区
      ---上海
    
        --松江
          --大学城
    def get_level(data):
        data_list=[]
        for item in data:
            if item['parent_id']==0:
                item['level']=0
            else:
                item['level']=1
            data_list.append(item)
        return data_list
    
    data=[
        {"cat_id":1,"name":"北京","parent_id":0},
        {"cat_id":2,"name":"上海","parent_id":0},
        {"cat_id":3,"name":"沙河","parent_id":1},
        {"cat_id":4,"name":"sb镇","parent_id":3},
        {"cat_id":5,"name":"昌平","parent_id":1},
        {"cat_id":6,"name":"青浦","parent_id":2},
    ]
    def get_tree(data):
        lists=[]
        tree={}
        for i in data:
            tree[i['cat_id']]=i
        for item in data:
            if not item['parent_id']:
                lists.append(tree[item['cat_id']])
            else:
                if "children" not in tree[item['parent_id']]:
                    tree[item['parent_id']]['children']=[]
                tree[item['parent_id']]['children'].append(tree[item['cat_id']])
        return lists
    # print(get_tree(data))
    res=[]
    def get_son(data,level=0,parent_id=0,is_clear=True):
        if is_clear:
            res.clear()
        for item in data:
            if item['parent_id']==parent_id:
                item['level']=level
                res.append(item)
                get_son(data,level=level+1,parent_id=item['cat_id'],is_clear=False)
        return res
    # son=get_son(data)
    # for i in son:
    #     print("-"*i['level']+i['name'])
    # 1北京 0
    #     2-海淀1
    #         4--sb镇2
    #     -昌平
    # 3 上海 0
    #     -青浦
    #     --徐泾镇
    #     -闵行
    res_id=[]
    def get_son_id(data,parent_id=0,is_clear=True):
        if is_clear:
            res_id.clear()
            if parent_id :
                res_id.append(parent_id)
    
        for item in data:
            if item['parent_id']==parent_id:
                res_id.append(item['cat_id'])
                get_son(data,parent_id=item['cat_id'],is_clear=False)
        return res_id
    
    import time ,random
    def get_order_id():
        st="012345679qwertyui"
        order_id=str(time.strftime("%Y%m%d%h%M%S"))+"".join(random.sample(st,5))
        return order_id

     商品分类列表

    前端部分

    后端

    class List(APIView):
        def post(self,request):
            param=request.data
            if param.get('category_id'):
                data=models.Category.objects.filter(is_show=True)
                data=Category_ser.Category_ser(instance=data,many=True,context={"request":request}).data
                all_id=func.get_son_id(data,param['category_id'])
                data=models.Product.objects.filter(disabled=True,cat_id__in=all_id).order_by("-w_order")
                data = Goods_ser.Goods_ser(instance=data, many=True, context={"request": request}).data
                return Response({"code": 200, "msg": "ok", "data": data})
            else:
                return Response({"code": 201, "msg":"缺少参数" })

    商品详情

    class Detail(APIView):
        def post(self,request):
            param=request.data
            if param.get("id"):
                data = models.Product.objects.filter(disabled=True,product_id=param.get("id")).first()
                if data:
                    data = Goods_ser.Goods_ser(instance=data, many=False, context={"request": request}).data
                    print(data)
                    return Response({"code": 200, "msg": "ok", "data": data})
                else:
                    return Response({"code": 201, "msg": "没有该商品"})

    前端

    <import src="../../wxParse/wxParse.wxml" />
    <navigation id='Navigation' show-icon="{{true}}" title="商品详情" show-title="{{true}}" class=""></navigation>
    <view class="container">
      
      <view class="swiper-container">
      
              <image src="{{goodsDetail.image_url}}" class="slide-image" lazy-load="true" />
      </view>
      <view class="goods-info">
        <view class="goods-left">
          <view class="goods-title">{{goodsDetail.name}}</view>
          <view class="goods-characteristic">{{goodsDetail.intor}}</view>    
            <view class="goods-price">Ұ {{goodsDetail.price}}</view>       
            <view class="piangjia">
              已售 {{goodsDetail.buy_count}}
            </view>     
        </view>
      </view> 
      <view class="tab-header" bindtap="tabFun">
        <view class="{{tabArr.curHdIndex=='0'? 'active' : ''}}" id="tab-hd01" data-id="0">商品介绍</view>
        <view class="{{tabArr.curHdIndex=='1'? 'active' : ''}}" id="tab-hd02" data-id="1">商品评价</view>
    
      </view>
      <view class="tab-container">
        <view class="tab-item {{tabArr.curBdIndex=='0'? 'active' : ''}}">
          <view class="goods-text">
            <template is="wxParse" data="{{wxParseData:article.nodes}}" />
          </view>
        </view>
        <view class="tab-item {{tabArr.curBdIndex=='1'? 'active' : ''}}">
          <view class="reputation-none" wx:if="{{!reputation}}">
            <image src="../../images/empty_comment.png" /> 还没有人评价
          </view>
          <view class="goods-reputa-list" wx:for="{{reputation}}" wx:key="id">
            <view class="goods-reputa-avatar">
              <image class="goods-avatar" src="{{item.user.avatarUrl}}"></image>
            </view>
            <view class="goods-reputa-mark">
              <view class="goods-reputa-user">
                {{item.user.nick}}
                <text>{{item.goods.goodReputationStr}}</text>
              </view>
              <view class="goods-mark">{{item.goods.goodReputationRemark}}</view>
              <view class="goods-mark-day">
                {{item.goods.dateReputation}}
                <text>{{item.goods.property}}</text>
              </view>
            </view>
          </view>
        </view>
      </view>
    
        <view class="footer-box">
          <view class="box-list">
            <image src="../../images/goods_service.png"></image>
            <button open-type="contact" session-from="weapp"></button>
          </view>
          <view class="box-list" bindtap="goShopCar">
            <image src="../../images/shopping_cart.png"></image>
            <view class="shop-num">{{shopNum}}</view>
          </view>
          <view class="box-list" >
         
          </view>
          <view class="box-title">
            <view class="box-shop-cart npx" bindtap="tobuy">立即购买</view>
          </view>
          <view class="box-title buy-now">
            <view class="box-now-buy npx" bindtap="toAddShopCar">加入购物车1</view>
          </view>
        </view>
     
      <view class="show-popup" hidden="{{hideShopPopup}}">
        <view class="popup-mask" bindtap="closePopupTap"></view>
        <view class="popup-contents">
          <view class="pop-goods-info">
            <view class="pop-img-box">
              <image src="{{goodsDetail.image_url}}" class="goods-thumbnail" />
            </view>
            <view class="pop-goods-des">
              <view class="pop-goods-title">{{goodsDetail.name}}</view>
              <view class="pop-goods-price" >¥ {{goodsDetail.price}}</view>
              
            </view>
            <view class="pop-goods-close" bindtap="closePopupTap"></view>
          </view>
         
          <view class="buy-num-box">
            <view class="num-label">购买数量</view>
            <view class="num-box">
              <view class="num-jian {{buyNumber == buyNumMin ? 'hui': ''}}" bindtap="numJianTap">-</view>
              <view class="num-input">
                <input type="number" value="{{buyNumber}}" disabled/>
              </view>
              <view class="num-jia {{buyNumber== buyNumMax ? 'hui': ''}}" bindtap="numJiaTap">+</view>
            </view>
          </view>
          <view class="popup-join-btn" wx:if="{{shopType =='addShopCar'}}" bindtap="addShopCar">加入购物车</view>
          <view class="popup-join-btn" wx:if="{{shopType =='tobuy'}}" bindtap="buyNow"> 立即购买</view>
         
        </view>
      </view>
    </view>
    View Code

    事务的隔离级别

      事务的四大特性分别是:原子性、一致性、隔离性、持久性

    解释

    """
    原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
    一致性: 执行事务前后,数据保持一致;
    隔离性: 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
    持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
    """

    并发事务带来的问题

      在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。

    并发虽然是必须的,但可能会导致一下的问题。

    脏读(Dirty read):

       事务T1正在操作一条数据,此时事务T2获取该条数据纪录,如果T1异常,事务回滚,T2读取到的数据就是脏数据,这种现象称为脏读。

    不可重复读(Unrepeatableread): 

       事务T1多次读取某条记录,在读取间隔中,事务T2更新了该技术的数据,当T1再次读取该记录时,获取到的数据不一致,这种现象称为不可重复读。产生的原因主要是数据的更新。

    幻读(Phantom read): 

      幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,

    第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

    可重复读(Repeatable read):

       ①定义:就是一个事务对同一份数据读取到的相同,不在乎其他事务对数据的修改。MySQL默认的隔离级别。

       ②缺点:会产生幻读。

    序列化(Serializable)

      ①定义:事务串行化执行,隔离级别最高,牺牲了系统的并发性。

       ②缺点:可以解决并发事务的所有问题。但是效率地下,消耗数据库性能,一般不使用。

     乐观锁和悲观锁

    概念

    #悲观锁:总是假设最坏的情况,认为竞争总是存在,每次拿数据的时候都认为会被修改,因此每次都会先上锁。其他线程阻塞等待释放锁。
    
    #乐观锁:总是假设最好的情况,认为竞争总是不存在,每次拿数据的时候都认为不会被修改,因此不会先上锁,在最后更新的时候比较数据有无更新,可通过版本号或CAS实现。

    两种锁的使用场景

    悲观锁:用于写比较多的情况,避免了乐观锁不断重试从而降低性能。
    乐观锁:用于读比较多的情况,避免了不必要的加锁的开销。

    加入购物车订单分析

    前端

     订单表的设计

    # 订单表
    class Order(models.Model):
        order_id = models.CharField(max_length=50, unique=True, primary_key=True)
        status_choices = (("active", '活动订单'), ("dead", '作废订单'), ("finish", '已完成订单'))
        status = models.CharField(choices=status_choices, default="active", max_length=50)
        pay_status_choices = ((0, '未付款'), (1, '已付款'))
        pay_status = models.SmallIntegerField(choices=pay_status_choices, default=0)
        payed = models.DecimalField(max_digits=10, decimal_places=2,default=0)
        order_total = models.DecimalField(max_digits=10, decimal_places=2,default=0)
        ship_status_choices = ((0, '未发货'), (1, '已发货'))
        pay_app = models.CharField(max_length=100)
        wxuser = models.ForeignKey(to="Wxuser", to_field="id", related_name="Order", db_constraint=False,on_delete=models.CASCADE)
        quantity = models.IntegerField(default=0)
        memo = models.CharField(max_length=200, default=0)
        consignee_name = models.CharField(max_length=200, default=0)
        consignee_area = models.CharField(max_length=200, default=0)
        consignee_address = models.CharField(max_length=200, default=0)
        consignee_zip = models.CharField(max_length=200, default=0)
        consignee_mobile = models.CharField(max_length=200,default=0)
        creat_time = models.DateTimeField(auto_now_add=True)
        update_time = models.DateTimeField(auto_now=True)
        def __str__(self):
            return self.order_id

    商品订单的实现

    from rest_framework.views import APIView
    from rest_framework.response import  Response
    from django.core.cache import cache
    from  app01 import models
    from app01.comment import func
    import hashlib,time
    from django.db import transaction
    
    
    from django import forms
    class OrderForm(forms.Form):
        phone = forms.CharField(
            error_messages={
                "required": "手机号不能为空"
            },
            # 调用Form组件中的验证器来校验手机号
           # validators=[RegexValidator(r'1[1-9][0-9]{9}', '手机号格式不正确')],
        )
        token = forms.CharField( error_messages={
                "required": "token不能为空"
            })
        province=forms.CharField( error_messages={
                "required": "省份不能为空"
            })
        city = forms.CharField(error_messages={
            "required": "城市不能为空"
        })
        county = forms.CharField(error_messages={
            "required": "县/区不能为空"
        })
        address = forms.CharField(error_messages={
            "required": "详细地址不能为空"
        })
        name = forms.CharField(error_messages={
            "required": "姓名不能为空"
        })
    
    class Creat(APIView):
        @transaction.atomic
        def post(self,request):
            param=request.data
            form_obj=OrderForm(param)
            if form_obj.is_valid() and param['buy_list']:
                user_cache=cache.get(param['token'])
                if user_cache:
                    openid=user_cache.split("&")[0]
                    user_data=models.Wxuser.objects.filter(openid=openid).first()
                    order_data = {"consignee_mobile": param['phone'],
                                  'consignee_name': param['name'],
                                  'wxuser_id': user_data.id,
                                  "memo": param['remark'],
                                  "consignee_area":f"{param['province']},{param['city']},{param['county']}",
                                  "consignee_address":param['address'] ,
                                  }
    
                    buy_list=param['buy_list']
                    goods_key=list(buy_list.keys())
                    all_product=models.Product.objects.filter(product_id__in=goods_key)
                    order_data['order_id']=func.get_order_id()
                    order_data['order_total']=0
                    order_data['quantity']=0
                    sid=transaction.savepoint()
                    for product in all_product:
                        product.product_id=str(product.product_id)
                        order_data['order_total']+=product.price*buy_list[product.product_id]
                        order_data['quantity']+=buy_list[product.product_id]
    
                        #创建子订单
                        for i in range(3):
                            stock=product.stock.quantity
                            new_stock=stock-buy_list[product.product_id]
                            if new_stock<0:
                                transaction.rollback(sid)
                                return Response({"code":203,"msg":f"{product.name}库存不足"})
                            res=models.Stock.objects.filter(quantity=stock,stock_id=product.stock.stock_id).update(quantity=new_stock)
                            if not  res:
                                if i==2:
                                    transaction.rollback(sid)
                                    return Response({"code": 203, "msg": f"创建订单失败"})
                                else:
                                    continue
                            else:
                                break
                        new_buy_count = product.buy_count + buy_list[product.product_id]
                        models.Product.objects.filter(product_id=product.product_id).update(buy_count=new_buy_count)
                        order_item_data={'order_id': order_data['order_id'], 'product_id': product.product_id, 
                                       "name": product.name, "image": product.image, "price": product.price, 
                                       "nums": buy_list[product.product_id], "brief": product.brief}
                        models.Order_items.objects.create(**order_item_data)
    
                        #models.Order_items.objects.create(**order_item_data)
                    models.Order.objects.create(**order_data)
    
                else:
                    return Response({"code":202,"msg":"token已过期"})
            else:
                return Response({"code":201,"msg":"缺少参数"})

     

     

      

      

      

  • 相关阅读:
    Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源
    Spring Boot 如何给微信公众号返回消息
    Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate
    Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置
    Spring Boot 开发微信公众号后台
    Spring Boot2 系列教程(十七)SpringBoot 整合 Swagger2
    Spring Boot2 系列教程(十六)定时任务的两种实现方式
    Spring Boot2 系列教程(十五)定义系统启动任务的两种方式
    Spring Boot2 系列教程(十四)CORS 解决跨域问题
    JavaScript二维数组
  • 原文地址:https://www.cnblogs.com/Gaimo/p/11827857.html
Copyright © 2011-2022 走看看