Django中实现事务的几种方式
# https://zhuanlan.zhihu.com/p/622987268 Django是支持事务操作的,它的默认事务行为是自动提交, 具体表现形式为:每次数据库操作(比如调用save()方法)会立即被提交到数据库中。 但是如果你希望把连续的SQL操作包裹在一个事务里,就需要手动开启事务 # 根据粒度不同,三种 ######## 全局########## -全局,每次请求在一个事务中,粒度太大,事务时间很长 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'lqz', 'HOST': '127.0.0.1', 'PORT': '3306', 'USER': 'lqz', 'PASSWORD': 'lqz123', #全局开启事务,绑定的是http请求响应整个过程 'ATOMIC_REQUESTS': True, } } # 局部禁用全局事务 from django.db import transaction # 局部禁用事务 @transaction.non_atomic_requests def seckill(request): return HttpResponse('秒杀成功') # 多数据库,用default的视图不受事务控制 @transaction.non_atomic_requests(using='default') def seckill(request): return HttpResponse('秒杀成功') ####### 视图开启事务############## # fbv开启 from django.db import transaction @transaction.atomic def seckill(request): return HttpResponse('秒杀成功') # cbv开启 from django.db import transaction from rest_framework.views import APIView class SeckillAPIView(APIView): @transaction.atomic def post(self, request): pass ################ 局部使用事务##################### from django.db import transaction def seckill(request): with transaction.atomic(): save() update() return HttpResponse('秒杀成功')
事物的回滚和保存点
# 1 普通事务操作(手动操作) transaction.atomic() # 开启事务 transaction.commit() # 提交事务 transaction.rollback() # 回滚事务 # 2 可以使用上下文管理器来控制(自动操作) with transaction.atomic(): # 自动提交和回滚 # 3 保存点 -开启事务 干了点事 设置保存点1 干了点事 设置一个保存点2 干了点事 回滚到干完第二个事,回滚到保存点2 ''' 在事务操作中,我们还会经常显式地设置保存点(savepoint) 一旦发生异常或错误,我们使用savepoint_rollback方法让程序回滚到指定的保存点 如果没有问题,就使用savepoint_commit方法提交事务 ''' from .models import Book from django.db import transaction def seckill(request): with transaction.atomic(): # 设置回滚点,一定要开启事务 sid = transaction.savepoint() print(sid) try: book = Book.objects.get(pk=1) book.name = '红楼梦' book.save() except Exception as e: # 如发生异常,回滚到指定地方 transaction.savepoint_rollback(sid) print('出异常了,回滚') # 如果没有异常,显式地提交一次事务 transaction.savepoint_commit(sid) return HttpResponse('秒杀成功') transaction.atomic() # 开启事务 sid = transaction.savepoint() # 设置保存点 transaction.savepoint_rollback(sid) # 回滚到保存点 transaction.savepoint_commit(sid) #提交保存点
事务提交后,执行某个回调函数
# 有的时候我们希望当前事务提交后立即执行额外的任务,比如客户下订单后立即邮件通知卖家 ###### 案例一################## def send_email(): print('发送邮件给卖家了') def seckill(request): with transaction.atomic(): # 设置回滚点,一定要开启事务 sid = transaction.savepoint() print(sid) try: book = Book.objects.get(pk=1) book.count = book.count-1 book.save() except Exception as e: # 如发生异常,回滚到指定地方 transaction.savepoint_rollback(sid) else: transaction.savepoint_commit(sid) #transaction.on_commit(send_email) transaction.on_commit(lambda: send_sms.delay('1898288322')) return HttpResponse('秒杀成功') ##### 案例二:celery中使用### transaction.on_commit(lambda: send_sms.delay('1898288322'))
Djang实现悲观锁乐观锁案例
# 线上卖图书 -图书表 图书名字,图书价格,库存字段 -订单表: 订单id,订单名字 # 表准备 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) # 使用mysql DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'lqz', 'HOST': '127.0.0.1', 'PORT': '3306', 'USER': 'lqz', 'PASSWORD': '123', } } # 创建lqz数据库
原生MySQL悲观锁
begin; # 开启事务 select * from goods where id = 1 for update; # 行锁 # order表中加数据 update goods set stock = stock - 1 where id = 1; # 更新 commit; #提交事务
orm实现上述
#1 使用悲观锁实现下单 @transaction.atomic # 整个过程在一个事物中---》改两个表:book表减库存,订单表生成记录 def seckill(request): # 锁住查询到的book对象,直到事务结束 sid = transaction.savepoint() # 保存点 # 悲观锁: select_for_update() # 加锁了--》行锁还是表锁? 分情况,都有可能 # book = Book.objects.select_for_update().filter(pk=1).first() # 加悲观锁,行锁,锁住当前行 if book.count > 0: print('库存可以,下单') # 订单表插入一条 Order.objects.create(order_id=str(datetime.datetime.now()), order_name='测试订单') # 库存-1,扣减的时候,判断库存是不是上面查出来的库存,如果不是,就回滚 time.sleep(random.randint(1, 4)) # 模拟延迟 book.count=book.count-1 book.save() transaction.savepoint_commit(sid) # 提交,释放行锁 return HttpResponse('秒杀成功') else: transaction.savepoint_rollback(sid) #回滚,释放行锁 return HttpResponse('库存不足,秒杀失败')
乐观锁秒杀==》库存还有,有的人就没成功
# 2 乐观锁秒杀--普通版 @transaction.atomic def seckill(request): # 锁住查询到的book对象,直到事务结束 sid = transaction.savepoint() book = Book.objects.filter(pk=1).first() # 没加锁 count = book.count print('现在的库存为:%s' % count) if book.count > 0: print('库存可以,下单') Order.objects.create(order_id=str(datetime.datetime.now()), order_name='测试订单-乐观锁') # 库存-1,扣减的时候,判断库存是不是上面查出来的库存,如果不是,就回滚 # time.sleep(random.randint(1, 4)) # 模拟延迟 res = Book.objects.filter(pk=1, count=count).update(count=count - 1) if res >= 1: # 表示修改成功 transaction.savepoint_commit(sid) return HttpResponse('秒杀成功') else: # 修改不成功,回滚 transaction.savepoint_rollback(sid) return HttpResponse('被别人改了,回滚,秒杀失败') else: transaction.savepoint_rollback(sid) return HttpResponse('库存不足,秒杀失败')
标签:事务,transaction,savepoint,回滚,Django,book,sid From: https://www.cnblogs.com/zfq132/p/17865810.html