重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
前言
创新互联主营改则网站建设的网络公司,主营网站建设方案,app软件开发公司,改则h5小程序定制开发搭建,改则网站营销推广欢迎改则等地区企业咨询订单并发这个问题我想大家都是有一定认识的,这里我说一下我的一些浅见,我会尽可能的让大家了解如何解决这类问题。
在解释如何解决订单并发问题之前,需要先了解一下什么是数据库的事务。(我用的是mysql数据库,这里以mysql为例)
1) 事务概念
一组mysql语句,要么执行,要么全不不执行。
2) mysql事务隔离级别
Read Committed(读取提交内容)
如果是Django2.0以下的版本,需要去修改到这个隔离级别,不然乐观锁操作时无法读取已经被修改的数据
RepeatableRead(可重读)
这是这是Mysql默认的隔离级别,可以到mysql的配置文件中去修改;
transcation-isolation = READ-COMMITTED
在mysql配置文件中添加这行然后重启mysql就可以将事务隔离级别修改至Read Committed
其他事务知识这里不会用到就不浪费时间去做介绍了。
悲观锁:开启事务,然后给mysql的查询语句最后加上for update。
这是在干什么呢。可能大家有些不理解,其实就是给资源加上和多线程中加互斥锁一样的东西,确保在一个事务结束之前,别的事务无法对该数据进行操作。
下面是悲观锁的代码,加锁和解锁都是需要消耗CPU资源的,所以在订单并发少的情况使用乐观锁会是一个更好的选择。
class OrderCommitView(View): """悲观锁""" # 开启事务装饰器 @transaction.atomic def post(self,request): """订单并发 ———— 悲观锁""" # 拿到商品id goods_ids = request.POST.getlist('goods_ids') # 校验参数 if len(goods_ids) == 0 : return JsonResponse({'res':0,'errmsg':'数据不完整'}) # 当前时间字符串 now_str = datetime.now().strftime('%Y%m%d%H%M%S') # 订单编号 order_id = now_str + str(request.user.id) # 地址 pay_method = request.POST.get('pay_method') # 支付方式 address_id = request.POST.get('address_id') try: address = Address.objects.get(id=address_id) except Address.DoesNotExist: return JsonResponse({'res':1,'errmsg':'地址错误'}) # 商品数量 total_count = 0 # 商品总价 total_amount = 0 # 获取redis连接 conn = get_redis_connection('default') # 拼接key cart_key = 'cart_%d' % request.user.id # # 创建保存点 sid = transaction.savepoint() order_info = OrderInfo.objects.create( order_id = order_id, user = request.user, addr = address, pay_method = pay_method, total_count = total_count, total_price = total_amount ) for goods_id in goods_ids: # 尝试查询商品 # 此处考虑订单并发问题, try: # goods = Goods.objects.get(id=goods_id) # 不加锁查询 goods = Goods.objects.select_for_update().get(id=goods_id) # 加互斥锁查询 except Goodsgoods.DoesNotExist: # 回滚到保存点 transaction.rollback(sid) return JsonResponse({'res':2,'errmsg':'商品信息错误'}) # 取出商品数量 count = conn.hget(cart_key,goods_id) if count is None: # 回滚到保存点 transaction.rollback(sid) return JsonResponse({'res':3,'errmsg':'商品不在购物车中'}) count = int(count) if goods.stock < count: # 回滚到保存点 transaction.rollback(sid) return JsonResponse({'res':4,'errmsg':'库存不足'}) # 商品销量增加 goods.sales += count # 商品库存减少 goods.stock -= count # 保存到数据库 goods.save() OrderGoods.objects.create( order = order_info, goods = goods, count = count, price = goods.price ) # 累加商品件数 total_count += count # 累加商品总价 total_amount += (goods.price) * count # 更新订单信息中的商品总件数 order_info.total_count = total_count # 更新订单信息中的总价格 order_info.total_price = total_amount + order_info.transit_price order_info.save() # 事务提交 transaction.commit() return JsonResponse({'res':5,'errmsg':'订单创建成功'})
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。