悲观锁和乐观锁机制
1 乐观锁
通俗易懂的来讲,乐观锁每次读取数据时都会先检查一遍数据,如果数据被其他线程修改,就会更新数据
如何使用
eg:
这是一个乐观锁的实现案例
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.atomic
def 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': '创建成功'}
2 悲观锁
悲观锁则是在执行数据前就会假设数据会被其他线程修改,所以在执行过程中会对数据进行上锁,让数据处于锁定状态(这种方法往往依靠数据库提供的锁方法)
如何使用
使用select_for_update()方法
eg:
obj = 模型类名.objects.select_for_update().get(id=1)
3 适用场景
锁 | 适用场景 |
悲观锁 | 写入频繁 |
乐观锁 | 读取频繁 |