当前位置: 首页 > news >正文

django系列之事务操作

Django 默认的事务行为是自动提交,除非事务正在执行,否则每个查询将会马上自动提交到数据库。

1. 全局开启事务

在 Web 里,处理事务比较常用的方式是将每个请求封装在一个事务中。 在你想启用该行为的数据库中,把 settings 配置数据库中的参数 ATOMIC_REQUESTS 设置为 True。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'testdb', 
        'USER': 'root',  
        'PASSWORD': '123', 
        'HOST': '127.0.0.1',     
        'PORT': 3306,  
        'ATOMIC_REQUESTS': True  # 全局开启事务,和http请求的整个过程绑定在一起
    }
}

它是这样工作的:在调用视图方法前,Django 先生成一个事务。如果响应能正常生成,Django 会提交该事务。而如果视图出现异常,Django 则会回滚该事务。

如果你全局开启了事务,你仍然可以使用 non_atomic_requests 装饰器让某些视图方法不受事务控制,但需要注意的是,该装饰器仅作用于视图本身时才会生效,在DRF的viewset中不生效。

from django.db import transaction

@transaction.non_atomic_requests
def trans2():
    valid_data_test = {'gender': "male", 'birth': '2020-10-01', 'tele': 18812341234, 'addr': '南京市雨花台区'}
    res_test = AuthorDetail.objects.create(**valid_data_test)
    res_test += 1
    return Response(status=HTTP_202_ACCEPTED, data={"msg": "insert success"})

视图请求trans2被 @transaction.non_atomic_requests 装饰,不受全局事务配置的控制。
class AuthorViewSet(viewsets.ModelViewSet):
    serializer_class = AuthorDetailSerializer

    @transaction.non_atomic_requests
    @action(methods='post', detail=False)
    def trans(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            valid_data = serializer.validated_data
            AuthorDetail.objects.create(**valid_data)
        return Response(status=HTTP_202_ACCEPTED, data={"msg": "insert success"})
     
DRF的视图函数即使被 @transaction.non_atomic_requests 装饰,但是依旧被全局事务配置所控制,所以说 non_atomic_requests 仅作用于视图本身时才会生效。

2 局部开启事务

Django项目中局部开启事务,可以借助于transaction.atomic方法。使用它我们就可以创建一个具备原子性的代码块,一旦代码块正常运行完毕,所有的修改会被提交到数据库。反之,如果有异常,更改会被回滚。

两种方式对某个请求使用事务:

class AuthorViewSet(viewsets.ModelViewSet):
    serializer_class = AuthorDetailSerializer

    @transaction.atomic
    @action(methods='post', detail=False)
    def trans(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            valid_data = serializer.validated_data
            AuthorDetail.objects.create(**valid_data)
        return Response(status=HTTP_202_ACCEPTED, data={"msg": "insert success"})

@transaction.atomic
def trans2():
    valid_data_test = {'gender': "male", 'birth': '2020-10-01', 'tele': 18812341234, 'addr': '南京市雨花台区'}
    res_test = AuthorDetail.objects.create(**valid_data_test)
    res_test += 1
    return Response(status=HTTP_202_ACCEPTED, data={"msg": "insert success"})

对请求中的某个代码块使用事务:

with transaction.atomic():
    AuthorDetail.objects.create(**valid_data_test)

3. 显式开启保存点

在事务操作中,我们还会经常显式地设置保存点(savepoint)。一旦发生异常或错误,我们使用savepoint_rollback方法让程序回滚到指定的保存点。如果没有问题,就使用savepoint_commit方法提交事务。

class AuthorDetailViewSet(viewsets.ModelViewSet):

    serializer_class = AuthorDetailSerializer
    queryset = AuthorDetail.objects.all()

    @action(methods=["post"], detail=False)          # detail=False or True: True: 系统会自动在生成的路由中添加pk值
    def trans(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            valid_data = serializer.validated_data
            AuthorDetail.objects.create(**valid_data)
            valid_data_test = {'gender': "male", 'birthday': '2020-10-01', 'telephone': 18812341234, 'addr': '南京市雨花台区'}
            valid_data_test2 = {'gender': "male", 'birthday': '2020-10-02', 'telephone': 18812341234, 'addr': '南京市雨花台区'}
            with transaction.atomic():
                AuthorDetail.objects.create(**valid_data_test)
                sid = transaction.savepoint()
                try:
                    res_test2 = AuthorDetail.objects.create(**valid_data_test2)
                    res_test2 += 1
                except Exception:
                    transaction.savepoint_rollback(sid)
                    print("error and rollback")

                transaction.savepoint_commit(sid)
                print("commit success")

        return Response(status=HTTP_202_ACCEPTED, data={"msg": "insert success"})

4. 事务嵌套

事务嵌套,只有内外两层的事务都执行成功,那么事务才能最终被成功提交。如果内层事务执行失败,那么外层的事务也会失败,事务最终会提交失败。

class AuthorDetailViewSet(viewsets.ModelViewSet):

    serializer_class = AuthorDetailSerializer
    queryset = AuthorDetail.objects.all()

    @transaction.atomic		# 外层事务的执行成功与否,除了它本身外,还依赖于内层事务执行成功与否。
    @action(methods=["post"], detail=False)          # detail=False or True: True: 系统会自动在生成的路由中添加pk值
    def trans(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            valid_data = serializer.validated_data
            AuthorDetail.objects.create(**valid_data)	# 记录1
            valid_data_test = {'gender': "male", 'birthday': '2020-10-01', 'telephone': 18812341234, 'addr': '南京市雨花台区'}

            with transaction.atomic():		# 故意让内层的事务执行失败
                res_test = AuthorDetail.objects.create(**valid_data_test)	# 记录2
                res_test += 1	

        return Response(status=HTTP_202_ACCEPTED, data={"msg": "insert success"})

最终,我们查得数据库的记录1和记录2都没有入库。

相关文章:

  • Kali Linux 安装搭建 hadoop 平台 详细教程
  • 求职半年,十月成功拿到比亚迪offer,分享一波面经....
  • Mac 使用 scp 上传或下载文件/文件夹
  • Modbus网关实现设备之间的相互通信和数据共享
  • 代码与细节(一)
  • 广东广西大量工地建筑支模
  • 京东API商品详情页,商品列表数据,商品评论数据采集
  • 2023NOIP A层联测14-选举
  • BootStrap-前端框架
  • JVM第七讲:JVM 基础 - Java 内存模型详解
  • gitlab版本库安装
  • 微信公众号粉丝迁移步骤?
  • 如何使用 MiniGPT-v2
  • Base64编码
  • 制药企业液体制剂生产设备管理利器:中央设备状态监控系统CMS
  • 儿童带磁性写字板入驻亚马逊CPC认证怎么做?CPC认证是什么样子的解析
  • Android AMS——进程优先级更新(十八)
  • 网络库OKHTTP(2)面试题
  • uml知识点学习
  • css 特别样式记录
  • 著名医学翻译家王贤才逝世,享年91岁
  • 5月1日,全社会跨区域人员流动量完成33271.4万人次
  • 特朗普称将禁止伊朗石油买家与美国做生意
  • 陈颖已任上海黄浦区委常委、统战部部长
  • 空间站第八批科学实验样品返抵地球并交付科学家
  • 王毅谈金砖国家开展斡旋调解的经验和独特优势