django乐观锁、悲观锁商品秒杀简单demo

发布时间 2023-08-15 16:44:05作者: Gentry-Yang

悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁

下面是2个商品秒杀demo:

表模型

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()  #
    count = models.SmallIntegerField(verbose_name='库存')


class Order(models.Model):
    order_id = models.CharField(max_length=64)
    order_name = models.CharField(max_length=32)
# 悲观锁
def skill_pessimistic(request):
    with transaction.atomic():
        sid = transaction.savepoint()
        book = Book.objects.select_for_update().filter(pk=1).first()  # 加行锁 别人只能读不能改
        if book.count > 0:
            Order.objects.create(order_id=str(uuid.uuid4()), order_name="悲观锁抢到的书籍")
            book.count -= 1
            book.save()
            transaction.savepoint_commit(sid)
            return HttpResponse("抢购成功")
        else:
            transaction.savepoint_rollback(sid)
            return HttpResponse("抢购失败")
# 乐观锁
def skill_happy(request):
    with transaction.atomic():
        while True:
            sid = transaction.savepoint()
            book = Book.objects.filter(pk=2).first()
            print('现在的库存为:%s' % book.count)
            if book.count > 0:
                print("现在可以下单")
                Order.objects.create(order_id=str(uuid.uuid4()), order_name="乐观锁抢到的书籍")
                res = Book.objects.filter(pk=2, count=book.count).update(count=book.count - 1)
                """
                  res = Book.objects.filter(pk=2, count=book.count).first()
                  res.count-=1
                  res.save()
                  这种是错误的 实际上是执行了2条sql语句
                  select * form  book  where id=2 and count = ${count}
                  update book set count = ${count} - 1 where id= ${id}
                  
                  
                  只有在执行下面一条语句时候才真正的乐观锁
                  update book set count = ${count} - 1 where id=2 and count = ${count}
                """
                if res < 1:
                    transaction.savepoint_rollback(sid)
                    continue
                transaction.savepoint_commit(sid)
                return HttpResponse("抢购成功")
            else:
                transaction.savepoint_rollback(sid)
                return HttpResponse("抢购失败")

测试demo:

import requests
from threading import Thread


def skill_task(url):
    res = requests.get(f"http://127.0.0.1:8000/{url}/").text
    print(res)


if __name__ == '__main__':
    # 开启五个线程去秒杀商品
    for i in range(5):
        t = Thread(target=skill_task,args="skill_happy")
        t.start()