Django - ORM - 事务, 乐观锁, 悲观锁
事務
概念
Transaction
事務:一個最小的不可再分的工作單元;通常一個事務對應一個完整的業務(例如銀行賬戶轉賬業務,該業務就是一個最小的工作單元)
一個完整的業務需要批量的DML(insert、update、delete)語句共同聯合完成
事務只和DML語句 ( 數據庫操作語句 ) 有關,或者說DML語句才有事務。這個和業務邏輯有關,業務邏輯不同,DML語句的個數不同
特性
? 原子性(A) 事務是最小單位,不可再分
??一致性(C) 事務要求所有的DML語句操作的時候,必須保證同時成功或者同時失敗
??隔離性(I) 事務A和事務B之間具有隔離性
??持久性(D) 是事務的保證,事務終結的標志(內存的數據持久到硬盤文件中)
行為
??開啟事務 Start Transaction
??事務結束 End Transaction
??提交事務 Commit Transaction
??回滾事務 Rollback Transaction
標志
開啟標志
任何一條DML語句(insert、update、delete)執行,標志事務的開啟
結束標志
? 提交 成功的結束,將所有的DML語句操作歷史記錄和底層硬盤數據來一次同步
? 回滾 失敗的結束,將所有的DML語句操作歷史記錄全部清空
代碼庫
Django 自帶的代碼庫
from django.db import transaction使用
方式一, 直接使用將一段操作設置為事務
with transaction.atomic():...方式二, 裝飾器方式
@transaction.atomic def foo():....悲觀鎖
概念
總是假設最壞的情況,每次取數據時都認為其他線程會修改,所以都會加鎖(讀鎖、寫鎖、行鎖等)
當其他線程想要訪問數據時,都需要阻塞掛起。可以依靠數據庫實現,如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖
保證同一時刻只有一個線程能操作數據,其他線程則會被 block
運用場景
??無臟讀 上鎖數據保證一致, 因此無臟讀, 對臟讀不允許的環境悲觀鎖可以勝任
??無并行 悲觀鎖對事務成功性可以保證, 但是會對數據加鎖導致無法實現數據的并行處理.
??事務成功率高 上鎖保證一次成功, 因此在對數據處理的成功率要求較高的時候更適合悲觀鎖.
??開銷大 悲觀鎖的上鎖解鎖是有開銷的, 如果超大的并發量這個開銷就不容小視, 因此不適合在高并發環境中使用悲觀鎖
??一次性完成 如果樂觀鎖多次嘗試的代價比較大,也建議使用悲觀鎖, 悲觀鎖保證一次成功
實例
from django.shortcuts import render from django.http import HttpResponse from django.views.generic import View from django.db import transaction from 應用名.models import 模型類名# 類視圖 (并發,悲觀鎖) class MyView(View):@transaction.atomicdef post(self, request):# select * from 表名 where id=1 for update; # for update 就表示鎖,只有獲取到鎖才會執行查詢,否則阻塞等待。obj = 模型類名.objects.select_for_update().get(id=1)# 等事務提交后,會自動釋放鎖。return HttpResponse('ok')樂觀鎖
概念
總是認為不會產生并發問題,每次去取數據的時候總認為不會有其他線程對數據進行修改,因此不會上鎖
但是在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制或CAS操作實現。
如果發現數據被改了. 就進行事務回滾取消之前的操作
運用場景
??臟讀 樂觀鎖不涉及到上鎖的處理, 因此在數據并行需求的時候是更適合樂觀鎖,當然會產生臟讀, 不過用回滾取消掉了.
??高并發 相比起悲觀鎖的開銷, 樂觀鎖也是比悲觀鎖更適合于高并發場景
??事務成功率低 樂觀鎖不能保證每次事務的成功, 是使用回滾方式來保證數據一致性, 因此會導致事務成功率很低.
??讀多寫少 樂觀鎖適用于讀多寫少的應用場景,這樣可以提高并發粒度
??開銷小 可能會導致很多次的回滾都不能拿到正確的處理回應, 因此如果對成功性要求低,而且每次開銷小比較適合樂觀鎖
實例
from django.shortcuts import render from django.http import JsonResponse from django.views.generic import View from django.db import transaction from 應用名.models import GoodsSKU# 類視圖 (并發,樂觀鎖) class MyView(View):@transaction.atomicdef post(self, request):'''訂單創建'''count = 3 # 訂購3件商品# 設置事務保存點s1 = transaction.savepoint()# 樂觀鎖,最多嘗試5次for i in range(5):# 查詢商品的信息(庫存)try:sku = GoodsSKU.objects.get(id=1)except:# 商品不存在 transaction.savepoint_rollback(s1)return JsonResponse({'res': 1, 'errmsg': '商品不存在'})# 判斷商品的庫存if count > sku.stock:transaction.savepoint_rollback(s1)return JsonResponse({'res': 2, 'errmsg': '商品庫存不足'})# 更新商品的庫存和銷量orgin_stock = sku.stock # 原庫存 (數據庫隔離級別必須是Read Committed;如果是Repeatable Read,那么多次嘗試讀取的原庫存都是一樣的,讀不到其他線程提交更新后的數據。)new_stock = orgin_stock - count # 更新后的庫存new_sales = sku.sales + count # 更新后的銷量# update 商品表 set stock=new_stock, sales=new_sales where id=1 and stock = orgin_stock# 通過where子句中的條件判斷庫存是否進行了修改。(并發,樂觀鎖)# 返回受影響的行數res = GoodsSKU.objects.filter(id=1, stock=orgin_stock).update(stock=new_stock, sales=new_sales)if res == 0: # 如果修改失敗if i == 4:# 如果嘗試5次都失敗 transaction.savepoint_rollback(s1)return JsonResponse({'res': 3, 'errmsg': '下單失敗'})continue # 再次嘗試# 否則更新成功# 跳出嘗試循環break# 提交事務 transaction.savepoint_commit(s1)# 返回應答return JsonResponse({'res': 4, 'message': '創建成功'})?
轉載于:https://www.cnblogs.com/shijieli/p/10926198.html
總結
以上是生活随笔為你收集整理的Django - ORM - 事务, 乐观锁, 悲观锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: chmod 详解
- 下一篇: Hystrix 资料简单梳理