乐观锁与悲观锁使用场景及简单例子
-
定义
1、乐观锁:顾名思义,对每次的数据操作都保持乐观的态度,不担心数据会被修改,所以不会对数据进行上锁。由于数据没有上锁,这就存在数据会被多人读写的情况。所以每次修改数据的时候需要对数据进行判断是否被修改过。
2、悲观锁:与乐观锁相反,对每次的数据操作都保存悲观的态度,总是担心数据会被修改,所以在自己操作的时候会对数据上锁,防止在自己操作的时候被他人同时操作导致更新丢失。
-
使用场景
1、乐观锁:由于乐观锁的不上锁特性,所以在性能方面要比悲观锁好,比较适合用在DB的读大于写的业务场景。
2、悲观锁:对于每一次数据修改都要上锁,如果在DB读取需要比较大的情况下有线程在执行数据修改操作会导致读操作全部被挂载起来,等修改线程释放了锁才能读到数据,体验极差。所以比较适合用在DB写大于读的情况。
-
如何选择
- 响应速度:选择乐观锁。要么冲突失败要么快速成功。悲观锁则需要等待释放锁才能被执行
- 冲突频率:频率高的话不应选择乐观锁,需要重试好几次,代价大。而悲观锁保证成功率
- 重试代价:若重试代价大则选择悲观锁
乐观锁 和 悲观锁 ,事务在django中的使用
-
事务
from django.db import transaction def post(self,request) #申明事务开始 with transaction.atomic(): #创建还原点 save_id = transaction.savepoint() try: #成功,提交还原点 transaction.savepoint_commit(save_id) except: #失败再次执行 transaction.savepoint_rollback(save_id) return Response({"code":200})
-
悲观锁 (购买会员的写入任务)
悲观锁上锁:select_for_update() #导入事务 from django.db import transaction #悲观锁 class Shop_Vip(APIView): def get(self,request): #用户id id = 1 #vipid vip_class_id = 3 #购买数量 number = 20 #开启事务 with transaction.atomic(): #创建还原点 save_id = transaction.savepoint() try: #查询用户 users = User.objects.get(id=id) print('user',users) #查找vip,并上锁 vip_class = Vips.objects.select_for_update().get(id=vip_class_id) print('vip_class',vip_class) #判断库从是否够 if vip_class.numbers <= number: return Response({'message':'库从不足'}) #库存够 #修改当前用户会员状态 users.vip_id = vip_class.id #修改会员库存数量 print('vip_class_number',vip_class.numbers) vip_class.numbers -= number #保存 users.save() vip_class.save() print('vip_class_number',vip_class.numbers) #成功 提交事务 transaction.savepoint_commit(save_id) return Response({'code':200}) except Exception as e: #失败 回滚事务 transaction.savepoint_rollback(save_id) return Response({'code':500})
-
乐观锁
#乐观锁 #开启事务 with transaction.atomic(): #创建还原点 save_id = transaction.savepoint() try: #查询用户 users = User.objects.get(id=id) while True: #查找vip,并上锁 vip_class = Vips.objects.get(id=vip_class_id) #判断库从是否够 if vip_class.numbers <= number: return Response({'message':'库从不足'}) #修改会员库存数量 new_numbers = vip_class.numbers - number print('new_numbers',new_numbers) #判断上一次结果和本次是否一样, 并修改 result = Vips.objects.filter(id=vip_class_id,numbers=vip_class.numbers).update(numbers=new_numbers) # 失败 跳出本次循环继续下一次循环 if result == 0: continue #结束死循环 else: break #成功 提交事务 #修改用户状态 users.vip_id = vip_class.id users.save() print('vip_class_number',vip_class.numbers) transaction.savepoint_commit(save_id) return Response({'code':200}) except Exception as e: # print('errors',e) #失败 回滚事务 transaction.savepoint_rollback(save_id) return Response({'code':500})