乐观锁,悲观锁
悲观锁乐观锁的实现
from django.shortcuts import render, HttpResponse
# Create your views here.
from .models import Book, Order
from django.db import transaction
### 回滚点的使用
# def seckill(request):
# with transaction.atomic():
# # 设置回滚点,一定要开启事务
# sid = transaction.savepoint()
# print(sid)
# try:
# book = Book.objects.get(pk=1)
# book.name = 'xxx'
# book.save() # 没有提交
# Order.objects.get(pk=1)
# transaction.savepoint_commit(sid)
# except Exception as e:
# # 如发生异常,回滚到指定地方
# transaction.savepoint_rollback(sid)
# print('出异常了,回滚')
#
# return HttpResponse('秒杀成功')
##提交事务后执行的函数
# def send_email():
# print('发送邮件给卖家了')
#
#
# def seckill(request):
# with transaction.atomic():
# book = Book.objects.get(pk=1)
# book.count = book.count - 1
# book.save()
# transaction.on_commit(send_email)
# return HttpResponse('秒杀成功')
### 悲观锁的使用 mysql的行锁做悲观锁
# Django中使用悲观锁锁定一个对象,需要使用select_for_update()方法。它本质是一个行级锁,能锁定所有匹配的行,如果查询所有,可以锁住整张表,直到事务结束
# import datetime
# import time
# import random
# @transaction.atomic
# def seckill(request):
# # 锁住查询到的book对象,直到事务结束
# sid = transaction.savepoint()
# book = Book.objects.select_for_update().filter(pk=1).first() # 加悲观锁,指导这个(事务)视图函数结束,锁才释放
# if book.count > 0:
# print('库存可以,下单')
# Order.objects.create(order_id=str(datetime.datetime.now()), order_name='测试订单')
# # 库存-1,扣减的时候,判断库存是不是上面查出来的库存,如果不是,就回滚
# time.sleep(4) # 模拟延迟
# book.count=book.count-1
# book.save()
# transaction.savepoint_commit(sid)
# return HttpResponse('秒杀成功')
# else:
# transaction.savepoint_rollback(sid)
# return HttpResponse('库存不足,秒杀失败')
# 乐观锁
import datetime
@transaction.atomic
def seckill(request):
# 锁住查询到的book对象,直到事务结束
### 乐观锁可能会失败,我们一直尝试秒杀,直到秒成功或库存不足
while True:
sid = transaction.savepoint()
book = Book.objects.filter(pk=1).first() # 没加锁
count = book.count
print('现在的库存为:%s' % count)
if book.count > 0:
print('库存可以,下单')
Order.objects.create(order_id=str(datetime.datetime.now()), order_name='测试订单')
# 库存-1,扣减的时候,判断库存是不是上面查出来的库存,如果不是,就回滚
# time.sleep(random.randint(1, 4)) # 模拟延迟
res = Book.objects.filter(pk=1, count=count).update(count=count - 1)
print(res)
if res >= 1: # 表示修改成功
transaction.savepoint_commit(sid)
return HttpResponse('秒杀成功')
else: # 修改不成功,回滚
transaction.savepoint_rollback(sid)
print('被别人扣减了,继续秒杀')
continue
else:
transaction.savepoint_rollback(sid)
return HttpResponse('库存不足,秒杀失败')
路由层
from django.contrib import admin
from django.urls import path
from app01.views import seckill
urlpatterns = [
path('admin/', admin.site.urls),
path('seckill/', seckill),
]
测试代码
import requests
from threading import Thread
def task():
res = requests.get('http://127.0.0.1:8000/seckill/')
print(res.text)
if __name__ == '__main__':
for i in range(10):
t=Thread(target=task)
t.start()