乐观锁,悲观锁

悲观锁乐观锁的实现

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()
posted @ 2023-04-19 15:14  李阿鸡  阅读(16)  评论(0编辑  收藏  举报
Title