Django中-事务操作
事务干货:https://zhuanlan.zhihu.com/p/93067082
事务使用:https://www.cnblogs.com/oklizz/p/11240212.html
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
在写项目时,特别是view中,我们可能需要进行多个业务操作(不仅仅是操作sql)。比如说:在编辑case的接口,我需要对case对应的interface进行新增/修改/删除操作,以及对case进行更新操作;我需要这样实现:把这四个步骤当成个事务,当其中有一个步骤失败,则回滚不执行;只有都成功时,才执行这四个步骤。
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
atomic提供两种方案实现事务
1、with 语句用法:
with 语句用法:可以灵活的有选择性的把某些 MySQL 数据库的操作看做一个事务。而且不用关心视图的类型。
from django.db import transaction
def viewfunc(request):
# 这部分代码不在事务中,会被 Django 自动提交
......
with transaction.atomic():
# 这部分代码会在事务中执行
......
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
from django.db import transaction
# 创建保存点
save_id = transaction.savepoint()
# 回滚到保存点
transaction.savepoint_rollback(save_id)
# 提交从保存点到当前状态的所有数据库事务操作
transaction.savepoint_commit(save_id)
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
举个栗子:
1.创建一个项目,新建一个APP
2.通过ORM创建生成表
from django.db import models
class Goods(models.Model):
title = models.CharField(max_length=50, verbose_name='标题')
price = models.IntegerField(verbose_name='价格')
date = models.CharField(max_length=50, null=True, verbose_name='出发日期')
satisfaction = models.CharField(verbose_name='满意度', max_length=20)
img = models.ImageField(upload_to='static/img', null=True, blank=True)
sum_evaluate = models.IntegerField(verbose_name='总评价人数')
sum_number = models.IntegerField(verbose_name='总出游人数')
class Comment(models.Model):
comment = models.CharField(max_length=250, verbose_name='评论')
goods = models.ForeignKey(Goods, on_delete=models.CASCADE, null=True)
随便建2张表模拟一下·····
3.我们给数据库加两条数据,用来两个用户之间的数据添加
4.配置URL
5.创建对应的视图函数
class CommentView(APIView):
def post(self, request):
goods_id = request.data.get('goods_id')
comment = request.data.get('comment')
if not all([goods_id, comment]):
return Response({'code': 400, 'msg': '参数不全'})
else:
# 创建保存点
save_id = transaction.savepoint()
# 这部分代码不在事务中,会被 Django 自动提交
with transaction.atomic():
# 这部分代码会在事务中执行
try:
Comment.objects.create(goods_id=goods_id, comment=comment)
# Goods object (1)
# good_obj = Goods.objects.get(id=goods_id)
good_obj = Goods.objects.get(name=goods_id)
good_obj.sum_evaluate += 1
good_obj.save()
# 提交从保存点到当前状态的所有数据库事务操作
# transaction.savepoint_commit(save_id)
return Response({'code': 200, 'msg': '添加成功'})
except Exception as e:
#捕获异常回滚
transaction.savepoint_rollback(save_id)
return Response({'code': 400, 'msg': '添加失败', 'errors': e})
然后我们请求会进行一些数据添加
6.这样是没有办法体现出我们事务的原子性的 现在我们让他报错
# good_obj = Goods.objects.get(name=goods_id)
2、装饰器用法:
装饰器用法:整个视图中所有 MySQL 数据库的操作都看做一个事务,范围太大,不够灵活。而且无法直接作用于类视图
from django.db import transaction
@transaction.atomic
def index(request):
// ORM操作
return ....
# 这些代码会在一个事务中执行
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
from django.db import transaction
class CommentView(APIView):
@transaction.atomic
def post(self, request):
goods_id = request.data.get('goods_id')
comment = request.data.get('comment')
if not all([goods_id, comment]):
return Response({'code': 400, 'msg': '参数不全'})
else:
Comment.objects.create(goods_id=goods_id, comment=comment)
# Goods object (1)
# good_obj = Goods.objects.get(id=goods_id)
good_obj = Goods.objects.get(name=goods_id)
good_obj.sum_evaluate += 1
good_obj.save()
return Response({'code': 200, 'msg': '添加成功'})
注意:
在原子块中不要进行错误捕获
当退出原子块的时候,Django会去查看它是否正常退出或者是否有异常来确定是否提交或者回滚
如果你捕获并处理了原子块中的异常,可能会隐藏Django中发生问题的事实。这样可能会造成非预期的行为。