悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和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()
标签:count,transaction,demo,savepoint,django,book,秒杀,res,id
From: https://www.cnblogs.com/yangyucai/p/17631677.html