python之Django的入門08------事務管理、悲觀鎖、樂觀鎖
阿新 • • 發佈:2018-12-16
我們接著上一篇文章的基礎上,來繼續瞭解進一步的Django框架
一.事務管理
在實際專案裡,事務管理是一個很重要的內容。 他可以保證一系列類操作要不全部成功要不全部失敗。也可以保證當多個應用程式在併發訪問資料庫時,可以在這些應用程式之間提供一個隔離方法,以防止彼此的操作互相干擾。
特性:
原子性:一組操作,要麼成功,要麼撤回
穩定性:有非法資料,事務撤回,比如外來鍵連線
隔離性:事務是獨立執行的,一個事務的處理結果,影響了其他事務,其他事務會撤回
可靠性:當出現軟體或者硬體崩潰的情況,資料表會驅動日誌檔案進行重構修改
事務管理語句:
1.開啟一個事務管理
begin
2.提交操作,對於資料庫的操作是永久性的
commit / commit work
3.回滾會撤銷所有未被提交的操作
rollback / rollback work
事務的隔離級別:
1.讀取未被提交的內容(髒讀) read uncommitted
2.讀取提交的內容(資料庫預設的隔離級別) read committed
3.可重複讀(易引起幻讀)
4.可序列:最高級別,強制事務排序(本質是在每一個讀的資料行上加共享鎖,可能會帶來大量的超時現象和鎖競爭)
二、樂觀鎖
總是認為不會產生併發問題,每次去取資料的時候總認為不會有其他執行緒對資料進行修改,因此不會上鎖,但是在更新時會判斷其他執行緒在這之前有沒有對資料進行修改
三、悲觀鎖
總是假設最壞的情況,每次取資料時都認為其他執行緒會修改,所以都會加鎖(讀鎖、寫鎖、行鎖等),當其他執行緒想要訪問資料時,都需要阻塞掛起。可以依靠資料庫實現,如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖
四、例子
from django.db import transaction '''悲觀鎖下訂單(存在事務管理)''' class TradeCommitView(View): @transaction.atomic #裝飾器的方法實現事務管理 def post(self,request): '''設定儲存點用於事務管理''' sid1 = transaction.savepoint() user = request.user if not user.is_authenticated(): '''判斷是否登陸''' return redirect(reverse('car:index')) # 接收資料 car_id = request.POST.get('car_id') pay_method = request.POST.get('pay_style') address_id = request.POST.get('address') from datetime import datetime order_id = str(user.id) + datetime.now().strftime('%Y%m%d%H%M%S') # 運費(元) transport = 5000 if not all([car_id,pay_method,address_id]): return JsonResponse({'errmsg':'資料內容不完整'}) try: # car = CarDetail.objects.get(id=car_id) #悲觀鎖 car = CarDetail.objects.select_for_update().get(id=car_id) except: transaction.savepoint_rollback(sid1) return HttpResponse('車輛不存在') service = float(car.car_price) * 10000 * 0.04 if service < 3000: service = 3000 add = AddressInfo.objects.get(id=address_id) # sid1 = transaction.savepoint() #建立訂單 try: order_new = OrderInfo.objects.create( order_id = order_id, user = user, add = add, price = car.car_price, service_charge =service, freight =transport, # status = 0, # pay_method = online_pai_method = pay_method ) import time # time.sleep(30) if car.status != 1: #如果車輛不是上線狀態 transaction.savepoint_rollback(sid1) #回退到儲存點 return JsonResponse({'errmsg':'下單失敗'}) order_car =OrderCar.objects.create( oder=order_new, car_id = car, comment='') car.status = 0 car.save() except Exception as e: transaction.savepoint_rollback(sid1) return JsonResponse({'errmsg':e}) transaction.savepoint_commit(sid1) return HttpResponse('結束')
'''樂觀鎖下訂單(存在事務管理)'''
class TradeCommitView_le(View):
@transaction.atomic
def post(self, request):
'''設定儲存點用於事務管理'''
sid1 = transaction.savepoint()
user = request.user
if not user.is_authenticated():
'''判斷是否登陸'''
return redirect(reverse('car:index'))
# 接收資料
car_id = request.POST.get('car_id')
pay_method = request.POST.get('pay_style')
address_id = request.POST.get('address')
from datetime import datetime
order_id = str(user.id) + datetime.now().strftime('%Y%m%d%H%M%S')
# 運費(元)
transport = 5000
if not all([car_id, pay_method, address_id]):
return HttpResponse('資料內容不完整')
# 校驗資料的正確(作業)
try:
car = CarDetail.objects.get(id=car_id)
except:
pass
service = float(car.car_price) * 10000 * 0.04
if service < 3000:
service = 3000
add = AddressInfo.objects.get(id=address_id)
# sid1 = transaction.savepoint()
# 建立訂單
try:
order_new = OrderInfo.objects.create(
order_id=order_id,
user=user,
add=add,
price=car.car_price,
service_charge=service,
freight=transport,
# status = 0,
# pay_method =
online_pai_method=pay_method
)
#樂觀鎖。不是真正意思上的鎖,只是在更新前查詢,如果不符合條件就回滾,符合就繼續執行。
res = CarDetail.objects.filter(id=car_id,status=1).update(status=0)
print('res',res)
if res == 0 :
transaction.savepoint_rollback(sid1)
return HttpResponse('車輛不存在')
order_car = OrderCar.objects.create(
oder=order_new,
car_id=car,
comment='')
except Exception as e:
transaction.savepoint_rollback(sid1)
return JsonResponse({'errmsg': e})
transaction.savepoint_commit(sid1)
return render(request,'trade_pay.html',context={'order_id':order_id})