前言
創(chuàng)新互聯(lián)主營改則網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,app軟件開發(fā)公司,改則h5小程序定制開發(fā)搭建,改則網(wǎng)站營銷推廣歡迎改則等地區(qū)企業(yè)咨詢訂單并發(fā)這個問題我想大家都是有一定認識的,這里我說一下我的一些淺見,我會盡可能的讓大家了解如何解決這類問題。
在解釋如何解決訂單并發(fā)問題之前,需要先了解一下什么是數(shù)據(jù)庫的事務(wù)。(我用的是mysql數(shù)據(jù)庫,這里以mysql為例)
1) 事務(wù)概念
一組mysql語句,要么執(zhí)行,要么全不不執(zhí)行。
2) mysql事務(wù)隔離級別
Read Committed(讀取提交內(nèi)容)
如果是Django2.0以下的版本,需要去修改到這個隔離級別,不然樂觀鎖操作時無法讀取已經(jīng)被修改的數(shù)據(jù)
RepeatableRead(可重讀)
這是這是Mysql默認的隔離級別,可以到mysql的配置文件中去修改;
transcation-isolation = READ-COMMITTED
在mysql配置文件中添加這行然后重啟mysql就可以將事務(wù)隔離級別修改至Read Committed
其他事務(wù)知識這里不會用到就不浪費時間去做介紹了。
悲觀鎖:開啟事務(wù),然后給mysql的查詢語句最后加上for update。
這是在干什么呢。可能大家有些不理解,其實就是給資源加上和多線程中加互斥鎖一樣的東西,確保在一個事務(wù)結(jié)束之前,別的事務(wù)無法對該數(shù)據(jù)進行操作。
下面是悲觀鎖的代碼,加鎖和解鎖都是需要消耗CPU資源的,所以在訂單并發(fā)少的情況使用樂觀鎖會是一個更好的選擇。
class OrderCommitView(View): """悲觀鎖""" # 開啟事務(wù)裝飾器 @transaction.atomic def post(self,request): """訂單并發(fā) ———— 悲觀鎖""" # 拿到商品id goods_ids = request.POST.getlist('goods_ids') # 校驗參數(shù) if len(goods_ids) == 0 : return JsonResponse({'res':0,'errmsg':'數(shù)據(jù)不完整'}) # 當前時間字符串 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':'地址錯誤'}) # 商品數(shù)量 total_count = 0 # 商品總價 total_amount = 0 # 獲取redis連接 conn = get_redis_connection('default') # 拼接key cart_key = 'cart_%d' % request.user.id # # 創(chuàng)建保存點 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: # 嘗試查詢商品 # 此處考慮訂單并發(fā)問題, 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':'商品信息錯誤'}) # 取出商品數(shù)量 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 # 保存到數(shù)據(jù)庫 goods.save() OrderGoods.objects.create( order = order_info, goods = goods, count = count, price = goods.price ) # 累加商品件數(shù) total_count += count # 累加商品總價 total_amount += (goods.price) * count # 更新訂單信息中的商品總件數(shù) order_info.total_count = total_count # 更新訂單信息中的總價格 order_info.total_price = total_amount + order_info.transit_price order_info.save() # 事務(wù)提交 transaction.commit() return JsonResponse({'res':5,'errmsg':'訂單創(chuàng)建成功'})
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。