Loading

Django中的事务操作

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中发生问题的事实。这样可能会造成非预期的行为。

posted @ 2020-11-14 23:24  就学45分钟  阅读(194)  评论(0编辑  收藏  举报