冲突比较少的时候,使用乐观锁。

冲突比较多的时候,使用悲观锁。

(1)     悲观锁

select * from df_goods_sku where id=17 for update;

悲观锁获取数据时对数据行了锁定,其他事务要想获取锁,必须等原事务结束。

视图函数views.py

from django.db import transaction  # 事务处理
class OrderCommitView(View):
'''订单创建'''
@transaction.atomic() # 事务处理装饰器
def post(self, request):
'''订单创建'''
# 判断用户是否登录
user = request.user
if not user.is_authenticated():
# 用户未登录
return JsonResponse({'res':0, 'errmsg':'用户未登录'}) # 接收参数
addr_id = request.POST.get('addr_id')
pay_method = request.POST.get('pay_method')
sku_ids = request.POST.get('sku_ids') # 1,3 # 校验参数
if not all([addr_id, pay_method, sku_ids]):
return JsonResponse({'res':1, 'errmsg':'参数不完整'}) # 校验支付方式
if pay_method not in OrderInfo.PAY_METHODS.keys(): # 需要在orders/model.py中添加PAY_METHODS字典
return JsonResponse({'res':2, 'errmsg':'非法的支付方式'}) # 校验地址
try:
addr = Address.objects.get(id=addr_id)
except Address.DoesNotExist:
# 地址不存在
return JsonResponse({'res':3, 'errmsg':'地址非法'}) # todo: 创建订单核心业务 # 组织参数
# 订单id: 20171122181630+用户id
order_id = datetime.now().strftime('%Y%m%d%H%M%S')+str(user.id) # 运费
transit_price = 10 # 总数目和总金额
total_count = 0
total_price = 0 # 设置保存点
save_id = transaction.savepoint()
try:
# todo: 向df_order_info表中添加一条记录
order = OrderInfo.objects.create(order_id=order_id,
user=user,
addr=addr,
pay_method=pay_method,
total_count=total_count,
total_price=total_price,
transit_price=transit_price) # todo: 用户的订单中有几个商品,需要向df_order_goods表中加入几条记录
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id sku_ids = sku_ids.split(',')
for sku_id in sku_ids:
# 获取商品的信息
try:
# 悲观锁
# select * from df_goods_sku where id=sku_id for update;
sku = GoodsSKU.objects.select_for_update().get(id=sku_id)
except:
# 商品不存在
transaction.savepoint_rollback(save_id) # 回滚到保存点
return JsonResponse({'res':4, 'errmsg':'商品不存在'}) # 查看谁拿到锁
print('user:%d stock:%d'%(user.id,sku.stock)) # 从redis中获取用户所要购买的商品的数量
count = conn.hget(cart_key, sku_id) # todo: 判断商品的库存
if int(count) > sku.stock:
transaction.savepoint_rollback(save_id) # 回滚到保存点
return JsonResponse({'res': 6, 'errmsg': '商品库存不足'}) # todo: 向df_order_goods表中添加一条记录
OrderGoods.objects.create(order=order,
sku=sku,
count=count,
price=sku.price) import time
time.sleep(10)
# todo: 更新商品的库存和销量
sku.stock -= int(count)
sku.sales += int(count)
sku.save() # todo: 累加计算订单商品的总数量和总价格
amount = sku.price*int(count)
total_count += int(count)
total_price += amount # todo: 更新订单信息表中的商品的总数量和总价格
order.total_count = total_count
order.total_price = total_price
order.save()
except Exception as e:
transaction.savepoint_rollback(save_id) # 回滚到保存点
return JsonResponse({'res': 7, 'errmsg': '下单失败'}) # 如果没失败则提交事务
transaction.savepoint_commit(save_id)
# todo: 清除用户购物车中对应的记录
conn.hdel(cart_key, *sku_ids) # 返回应答
return JsonResponse({'res':5, 'message':'创建成功'})

(2) 乐观锁

查询时不锁数据,提交更改时进行判断.

update df_goods_sku set stock=0, sales=1 where id=17 and stock=1;

使用乐观锁前,要先 设置mysql事务的隔离级别

打开mysql配置文件: sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf

添加下面一行代码

transaction-isolation = READ-COMMITTED

保存配置文件,重启mysql服务。

 sudo service mysql restart

实例views.py

class OrderCommitView(View):
'''订单创建'''
@transaction.atomic() # 事务处理装饰器
def post(self, request):
'''订单创建'''
# 判断用户是否登录
user = request.user
if not user.is_authenticated():
# 用户未登录
return JsonResponse({'res':0, 'errmsg':'用户未登录'}) # 接收参数
addr_id = request.POST.get('addr_id')
pay_method = request.POST.get('pay_method')
sku_ids = request.POST.get('sku_ids') # 1,3 # 校验参数
if not all([addr_id, pay_method, sku_ids]):
return JsonResponse({'res':1, 'errmsg':'参数不完整'}) # 校验支付方式
if pay_method not in OrderInfo.PAY_METHODS.keys(): # 需要在orders/model.py中添加PAY_METHODS字典
return JsonResponse({'res':2, 'errmsg':'非法的支付方式'}) # 校验地址
try:
addr = Address.objects.get(id=addr_id)
except Address.DoesNotExist:
# 地址不存在
return JsonResponse({'res':3, 'errmsg':'地址非法'}) # todo: 创建订单核心业务 # 组织参数
# 订单id: 20171122181630+用户id
order_id = datetime.now().strftime('%Y%m%d%H%M%S')+str(user.id) # 运费
transit_price = 10 # 总数目和总金额
total_count = 0
total_price = 0 # 设置保存点
save_id = transaction.savepoint()
try:
# todo: 向df_order_info表中添加一条记录
order = OrderInfo.objects.create(order_id=order_id,
user=user,
addr=addr,
pay_method=pay_method,
total_count=total_count,
total_price=total_price,
transit_price=transit_price) # todo: 用户的订单中有几个商品,需要向df_order_goods表中加入几条记录
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id sku_ids = sku_ids.split(',')
for sku_id in sku_ids:
for i in range(3): # 多次尝试
# 获取商品的信息
try:
sku = GoodsSKU.objects.select_for_update().get(id=sku_id)
except:
# 商品不存在
transaction.savepoint_rollback(save_id) # 回滚到保存点
return JsonResponse({'res':4, 'errmsg':'商品不存在'}) # 查看谁拿到锁
print('user:%d stock:%d'%(user.id,sku.stock)) # 从redis中获取用户所要购买的商品的数量
count = conn.hget(cart_key, sku_id) # todo: 判断商品的库存
if int(count) > sku.stock:
transaction.savepoint_rollback(save_id) # 回滚到保存点
return JsonResponse({'res': 6, 'errmsg': '商品库存不足'}) # todo: 更新商品的库存和销量
orgin_stock = sku.stock # 原有的库存
new_stock = orgin_stock - int(count) # 要修改的库存
new_sales = sku.sales + int(count) # 要修改的销量 # 返回受影响行数 查询是否成功 放在添加记录前先检测再添加 --乐观锁
res = GoodsSKU.objects.filter(id=sku_id, stock=orgin_stock).update(stock=new_stock, sales=new_sales)
if res == 0:
if i == 2:
# 尝试的第3次,失败了回滚
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 7, 'errmsg': '下单失败'})
continue # todo: 向df_order_goods表中添加一条记录
OrderGoods.objects.create(order=order,
sku=sku,
count=count,
price=sku.price) # todo: 累加计算订单商品的总数量和总价格
amount = sku.price*int(count)
total_count += int(count)
total_price += amount # 跳出循环
break # todo: 更新订单信息表中的商品的总数量和总价格
order.total_count = total_count
order.total_price = total_price
order.save()
except Exception as e:
transaction.savepoint_rollback(save_id) # 回滚到保存点
return JsonResponse({'res': 7, 'errmsg': '下单失败7'}) # 如果没失败则提交事务
transaction.savepoint_commit(save_id)
# todo: 清除用户购物车中对应的记录
conn.hdel(cart_key, *sku_ids) # 返回应答
return JsonResponse({'res':5, 'message':'创建成功'})

最新文章

  1. Oracle体系结构总结
  2. tomcat WEB-INF中的结构
  3. Spring+SpringMVC+MyBatis)
  4. linux命令(10)使用kill杀死含有指定关键字的进程
  5. 在Eclipse中查看JDK类库的源代码
  6. UVa 808 (建坐标系、找规律) Bee Breeding
  7. 【C语言】-循环结构-for语句
  8. hdu 5073 Galaxy
  9. 《转》JAVA动态代理(JDK和CGLIB)
  10. mysql经常使用命令总结
  11. hdu_Anniversary party_(树形DP入门题)
  12. Java NIO (三) 通道(Channel)
  13. [开源]基于Log4Net简单实现KafkaAppender
  14. zTree 3-- jQuery 树插件笔记
  15. Yarn架构详解
  16. js dictionary
  17. The module is an Android project without build variants, and cannot be built
  18. 好久没玩docker了,温下手
  19. 查看mysql数据库中的所有用户
  20. 【Struts2】result类型

热门文章

  1. Java Web 学习(4) —— Spring MVC 概览
  2. LeetCode解题笔记 - 3. Longest Substring Without Repeating Characters
  3. 【ECNU77】位与数对个数(数位DP)
  4. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 8
  5. LinkedTransferQueue
  6. sqlite3数据库最大可以是多大?可以存放多少数据?读写性能怎么样?
  7. Hive表导出成csv文件
  8. Java生鲜电商平台-SpringCloud微服务架构中核心要点和实现原理
  9. 尉蓝色的P2P金融众筹平台手机模板
  10. 怎么在CAD中测量图纸距离?来看看这两种方法