python乐观锁代码实现_Django的乐观锁与悲观锁实现

1)     事务概念

一组mysql语句,要么执行,要么全不不执行。

2)  mysql事务隔离级别

Read Committed(读取提交内容)

如果是Django2.0以下的版本,需要去修改到这个隔离级别,不然乐观锁操作时无法读取已经被修改的数据

RepeatableRead(可重读)

这是这是Mysql默认的隔离级别,可以到mysql的配置文件中去修改;

transcation-isolation = READ-COMMITTED

在mysql配置文件中添加这行然后重启mysql就可以将事务隔离级别修改至Read Committed

其他事务知识这里不会用到就不浪费时间去做介绍了。

悲观锁:开启事务,然后给mysql的查询语句最后加上for update。

这是在干什么呢。可能大家有些不理解,其实就是给资源加上和多线程中加互斥锁一样的东西,确保在一个事务结束之前,别的事务无法对该数据进行操作。

下面是悲观锁的代码,加锁和解锁都是需要消耗CPU资源的,所以在订单并发少的情况使用乐观锁会是一个更好的选择。

classOrderCommitView(View):"""悲观锁"""

#开启事务装饰器

@transaction.atomicdefpost(self,request):"""订单并发 ———— 悲观锁"""

#拿到商品id

goods_ids = request.POST.getlist('goods_ids')#校验参数

if len(goods_ids) ==0 :return JsonResponse({'res':0,'errmsg':'数据不完整'})#当前时间字符串

now_str = datetime.now().strftime('%Y%m%d%H%M%S')#订单编号

order_id = now_str +str(request.user.id)#支付方式

pay_method = request.POST.get('pay_method')#地址

address_id = request.POST.get('address_id')try:

address= Address.objects.get(id=address_id)exceptAddress.DoesNotExist:return JsonResponse({'res':1,'errmsg':'地址错误'})#商品数量

total_count =0#商品总价

total_amount =0#获取redis连接

conn = get_redis_connection('default')#拼接key

cart_key = 'cart_%d' %request.user.id# #创建保存点

sid =transaction.savepoint()

order_info=OrderInfo.objects.create(

order_id=order_id,

user=request.user,

addr=address,

pay_method=pay_method,

total_count=total_count,

total_price=total_amount

)for goods_id ingoods_ids:#尝试查询商品

#此处考虑订单并发问题,

try:#goods = Goods.objects.get(id=goods_id) # 不加锁查询

goods = Goods.objects.select_for_update().get(id=goods_id) #加互斥锁查询

exceptGoodsgoods.DoesNotExist:#回滚到保存点

transaction.rollback(sid)return JsonResponse({'res':2,'errmsg':'商品信息错误'})#取出商品数量

count =conn.hget(cart_key,goods_id)if count isNone:#回滚到保存点

transaction.rollback(sid)return JsonResponse({'res':3,'errmsg':'商品不在购物车中'})

count=int(count)if goods.stock

transaction.rollback(sid)return JsonResponse({'res':4,'errmsg':'库存不足'})#商品销量增加

goods.sales +=count#商品库存减少

goods.stock -=count#保存到数据库

goods.save()

OrderGoods.objects.create(

order=order_info,

goods=goods,

count=count,

price=goods.price

)#累加商品件数

total_count +=count#累加商品总价

total_amount += (goods.price) *count#更新订单信息中的商品总件数

order_info.total_count =total_count#更新订单信息中的总价格

order_info.total_price = total_amount +order_info.transit_price

order_info.save()#事务提交

transaction.commit()return JsonResponse({'res':5,'errmsg':'订单创建成功'})

然后就是乐观锁查询了,相比悲观锁,乐观锁其实并不能称为是锁,那么它是在做什么事情呢。

其实是在你要进行数据库操作时先去查询一次数据库中商品的库存,然后在你要更新数据库中商品库存时,将你一开始查询到的库存数量和商品的ID一起作为更新的条件,当受影响行数返回为0时,说明没有修改成功,那么就是说别的进程修改了该数据,那么你就可以回滚到之前没有进行数据库操作的时候,重新查询,重复之前的操作一定次数,如果超过你设置的次数还是不能修改那么就直接返回错误结果。

该方法只适用于订单并发较少的情况,如果失败次数过多,会带给用户不良体验,同时适用该方法要注意数据库的隔离级别一定要设置为Read Committed 。

classOrderCommitView(View):"""乐观锁"""

#开启事务装饰器

@transaction.atomicdefpost(self,request):"""订单并发 ———— 乐观锁"""

#拿到id

goods_ids = request.POST.get('goods_ids')if len(goods_ids) ==0 :return JsonResponse({'res':0,'errmsg':'数据不完整'})#当前时间字符串

now_str = datetime.now().strftime('%Y%m%d%H%M%S')#订单编号

order_id = now_str +str(request.user.id)#支付方式

pay_method = request.POST.get('pay_method')#地址

address_id = request.POST.get('address_id')try:

address= Address.objects.get(id=address_id)exceptAddress.DoesNotExist:return JsonResponse({'res':1,'errmsg':'地址错误'})#商品数量

total_count =0#商品总价

total_amount =0#订单运费

transit_price = 10

#创建保存点

sid =transaction.savepoint()

order_info=OrderInfo.objects.create(

order_id=order_id,

user=request.user,

addr=address,

pay_method=pay_method,

total_count=total_count,

total_price=total_amount,

transit_price=transit_price

)#获取redis连接

goods = get_redis_goodsection('default')#拼接key

cart_key = 'cart_%d' %request.user.idfor goods_id ingoods_ids:#尝试查询商品

#此处考虑订单并发问题,

#redis中取出商品数量

count =goods.hget(cart_key, goods_id)if count isNone:#回滚到保存点

transaction.savepoint_rollback(sid)return JsonResponse({'res': 3, 'errmsg': '商品不在购物车中'})

count=int(count)for i in range(3):#若存在订单并发则尝试下单三次

try:

goods= Goodsgoods.objects.get(id=goods_id) #不加锁查询

#goods = Goodsgoods.objects.select_for_update().get(id=goods_id) # 加互斥锁查询

exceptGoodsgoods.DoesNotExist:#回滚到保存点

transaction.savepoint_rollback(sid)return JsonResponse({'res':2,'errmsg':'商品信息错误'})

origin_stock=goods.stockprint(origin_stock, 'stock')print(goods.id, 'id')if origin_stock

transaction.savepoint_rollback(sid)return JsonResponse({'res':4,'errmsg':'库存不足'})## 商品销量增加

#goods.sales += count

## 商品库存减少

#goods.stock -= count

## 保存到数据库

#goods.save()

#如果下单成功后的库存

new_stock = goods.stock -count

new_sales= goods.sales +count

res= Goodsgoods.objects.filter(stock=origin_stock,id=goods_id).update(stock=new_stock,sales=new_sales)print(res)if res ==0:if i == 2:#回滚

transaction.savepoint_rollback(sid)return JsonResponse({'res':5,'errmsg':'下单失败'})continue

else:breakOrderGoods.objects.create(

order=order_info,

goods=goods,

count=count,

price=goods.price

)#删除购物车中记录

goods.hdel(cart_key,goods_id)#累加商品件数

total_count +=count#累加商品总价

total_amount += (goods.price) *count#更新订单信息中的商品总件数

order_info.total_count =total_count#更新订单信息中的总价格

order_info.total_price = total_amount +order_info.transit_price

order_info.save()#事务提交

transaction.savepoint_commit(sid)return JsonResponse({'res':6,'errmsg':'订单创建成功'})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值