首页 > 其他分享 >django中ORM开启事务

django中ORM开启事务

时间:2023-05-08 22:57:37浏览次数:46  
标签:事务 transaction 开启 django 回滚 ORM atomic Django

django中ORM开启事务

一、全局开启

ATOMIC_REQUESTS设置为True,每个请求过来时,Django会在调用视图方法前开启一个事务。如果请求正确处理并正确返回了结果,Django就会提交该事务,否则,Django会回滚该事务。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mxshop',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '123',
        'OPTIONS': {
            "init_command": "SET default_storage_engine='INNODB'",
       #'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", #配置开启严格sql模式
        }
        "ATOMIC_REQUESTS": True, # 全局开启事务,绑定的是http请求响应整个过程
        "AUTOCOMMIT":False,      # 全局取消自动提交,慎用
    },
  'other':{
    'ENGINE': 'django.db.backends.mysql', 
            ......
  }  # 还可以配置其他数据

对部分视图函数取消事务

from django.db import transaction

@transaction.non_atomic_requests
def my_view(request):
    do_stuff()

@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

强调:

Django官方文档中提到,不推荐开启全局事务。因为每个HTTP 请求都会捆绑一个事务,当流量上来的时候,性能会有影响。

二、局部开启

使用transaction.atomic(using=None, savepoint=True),atomic即原子性,我们就可以用该方法创建一个具备原子性的代码块。一旦代码块正常运行完毕,所有的修改会被提交到数据库。反之,如果有异常,更改会被回滚。

参数

using='other','other'对应的是settings.py中配置项DATABASES所指定的某个引擎,意思是当你使用other对应的引擎的时,这个事务才生效。

savepoint的意思是开启事务保存点。

用法1:作为上下文管理器来使用

from django.db import transaction

with transaction.atomisc():
    # sql1
    # sql2
    # sql3
    # 在with代码块内写的所有orm操作都是属于同一个事务

上述用法可以写在一个视图函数里

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():   #保存点
        # This code executes inside a transaction.
        do_more_stuff()

    do_other_stuff()

用法2:给视图函数装饰器

from django.db import transaction

@transaction.atomic
def post(self,request):
    ...
    sid=transaction.savepoint()  #开启事务
    ...
    transaction.savepoint_rollback(sid)  # 回滚
    ...
    transaction.savepoint_commit(sid)  # 提交

也可以进行异常处理

from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()

    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()

    add_children()

用法3:还可以嵌套使用

函数的事务嵌套上下文管理器的事务,上下文管理器的事务嵌套上下文管理器的事务等

from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()

    try:
        with transaction.atomic():
            generate_relationships()
       # other_task()  #还要注意一点,如果你在事务里面写了别的操作,只有这些操作全部完成之后,事务才会commit,也就是说,如果你这个任务是查询上面更改的数据表里面的数据,那么看到的还是事务提交之前的数据。
    except IntegrityError:
        handle_exception()

    add_children()

上述例子中,即使generate_relationships()中的代码打破了数据完整性约束,你仍然可以在add_children()中执行数据库操作,并且create_parent()产生的更改也有效。需要注意的是,在调用handle_exception()之前,generate_relationships()中的修改就已经被安全的回滚了。因此,如果有需要,你照样可以在异常处理函数中操作数据库。

强调:尽量不要在atomic代码块中捕获异常,原因如下

因为当atomic块中的代码执行完的时候,Django会根据代码正常运行来执行相应的提交或者回滚操作。如果在atomic代码块里面捕捉并处理了异常,就有可能隐盖代码本身的错误,从而可能会有一些意料之外的不愉快事情发生。

担心主要集中在DatabaseError和它的子类(如IntegrityError)。如果这种异常真的发生了,事务就会被破坏掉,而Django会在代码运行完后执行回滚操作。如果你试图在回滚前执行一些数据库操作,Django会抛出TransactionManagementError。通常你会在一个ORM相关的信号处理器抛出异常时遇到这个行为。

捕获异常的正确方式正如上面atomic代码块所示。如果有必要,添加额外的atomic代码块来做这件事情,也就是事务嵌套。这么做的好处是:当异常发生时,它能明确地告诉你那些操作需要回滚,而那些是不需要的。

为了保证原子性,atomic还禁止了一些API。像试图提交、回滚事务,以及改变数据库连接的自动提交状态这些操作,在atomic代码块中都是不予许的,否则就会抛出异常。

下面是Django的事务管理代码:

• 进入最外层atomic代码块时开启一个事务;

• 进入内部atomic代码块时创建保存点;

• 退出内部atomic时释放或回滚事务;注意如果有嵌套,内层的事务也是不会提交的,可以释放(正常结束)或者回滚

• 退出最外层atomic代码块时提交或者回滚事务;

你可以将保存点参数设置成False来禁止内部代码块创建保存点。如果发生了异常,Django在退出第一个父块的时候执行回滚,如果存在保存点,将回滚到这个保存点的位置,否则就是回滚到最外层的代码块。外层事务仍然能够保证原子性。然而,这个选项应该仅仅用于保存点开销较大的时候。毕竟它有个缺点:会破坏上文描述的错误处理机制。

注意:transaction只对数据库层的操作进行事务管理,不能理解为python操作的事务管理

def example_view(request):
    tag = False
    with transaction.atomic():
        tag = True
        change_obj() # 修改对象变量
        obj.save()
        raise DataError
    print("tag = ",tag) #结果是True,也就是说在事务中的python变量赋值,即便是事务回滚了,这个赋值也是成功的

还要注意:如果你配置了全局的事务,它和局部事务可能会产生冲突,你可能会发现你局部的事务完成之后,如果你的函数里面其他的sql除了问题,也就是没在这个上下文管理器的局部事务包裹范围内的函数里面的其他的sql出现了问题,你的局部事务也是提交不上的,因为全局会回滚这个请求和响应所涉及到的所有的sql,所以还是建议以后的项目尽量不要配置全局的事务,通过局部事务来搞定,当然了,看你们的业务场景。

transaction的其他方法

@transaction.atomic
def viewfunc(request):

  a.save()
  # open transaction now contains a.save()
  sid = transaction.savepoint()  #创建保存点

  b.save()
  # open transaction now contains a.save() and b.save()

  if want_to_keep_b:
      transaction.savepoint_commit(sid) #提交保存点
      # open transaction still contains a.save() and b.save()
  else:
      transaction.savepoint_rollback(sid)  #回滚保存点
      # open transaction now contains only a.save()

  transaction.commit() #手动提交事务,默认是自动提交的,也就是说如果你没有设置取消自动提交,那么这句话不用写,如果你配置了那个AUTOCOMMIT=False,那么就需要自己手动进行提交。

为保证事务的隔离性,我们还可以结合上面的锁来实现,也就是说在事务里面的查询语句,咱们使用select_for_update显示的加锁方式来保证隔离性,事务结束后才会释放这个锁,例如:(了解)

@transaction.atomic ## 轻松开启事务
def handle(self):
    ## 测试是否存在此用户
    try:
        ## 锁定被查询行直到事务结束
        user = 
    User.objects.select_for_update().get(open_id=self.user.open_id)
        #other sql 语句
    except User.DoesNotExist:
        raise BaseError(-1, 'User does not exist.')

通过Django外部的python脚本来测试一下事务:

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

    import datetime
    from app01 import models

    try:
        from django.db import transaction
        with transaction.atomic():
            new_publisher = models.Publisher.objects.create(name="火星出版社")
            models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10)  # 指定一个不存在的出版社id
    except Exception as e:
        print(str(e))

标签:事务,transaction,开启,django,回滚,ORM,atomic,Django
From: https://www.cnblogs.com/ycmyay/p/17383408.html

相关文章

  • Transformer 估算 101
    Transformer估算101 本文主要介绍用于估算transformer类模型计算量需求和内存需求的相关数学方法。引言其实,很多有关transformer语言模型的一些基本且重要的信息都可以用很简单的方法估算出来。不幸的是,这些公式在NLP社区中鲜为人知。本文的目的是总结这些公式,阐明......
  • Django高级之-cookie与session
    目录1背景信息cookie的介绍cookie的由来什么是cookiecookie的原理Cookie规范Cookie的覆盖在浏览器中查看cookiesession的介绍session的由来什么是sessiontoken的介绍token的由来什么是token?Django操作cookie设置cookie获取cookie删除CookieCookie版登录校验案例Django操作Session......
  • ORM常用字段和参数
    一些说明:表myapp_person的名称是自动生成的,如果你要自定义表名,需要在model的Meta类中指定db_table参数,强烈建议使用小写表名,特别是使用MySQL作为后端数据库时。id字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定primary_key=True即可。如果Django发现你......
  • ORM
    ORM一、Django模型层之ORM介绍ORM是什么?为何要有ORM?我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(增、删、改、查),而一旦谈到数据的管理操作,就需要用到数据库管理软件,例如mysql、oracle、MicrosoftSQLServer等。如果应用程序需要操作数据(比如将......
  • Django笔记三十八之发送邮件
    本文首发于公众号:Hunter后端原文链接:Django笔记三十八之发送邮件这一篇笔记介绍如何在Django中发送邮件。在Python中,提供了smtplib的邮件模块,而Django在这个基础上对其进行了封装,我们可以通过django.core.mail来调用。以下是本篇笔记的目录:邮件配置项send_mail......
  • Web框架与Django简介
    Web框架与Django简介一、Web应用的组成我们接下来学习的目的就是为了开发一个Web应用软件。那到底什么是Web应用软件呢?对于传统的应用软件来说,基本上都是部署于单机使用的,而Web应用软件则不一样,Web应用软件是基于B/S架构的,B与S部署于不同的计算机上,并且基于网络通信,所以B与S的......
  • Django之csrf跨站请求
    目录CSRF_TOKEN跨站请求伪造在form表单中应用:在Ajax中应用:关于CSRF中间件的全站禁用和局部禁用在CBV中使用:CSRF_TOKEN跨站请求伪造介绍:浅谈CSRF(Cross-siterequestforgery)跨站请求伪造在form表单中应用:<formaction=""method="post">{%csrf_token%}<p>用户名:<in......
  • Django框架简介
    python主流web框架django大而全自带的功能非常的多但是有时候会略显笨重类似于'航空母舰'flask小而精自带的功能非常的少但是第三方模块非常的多类似于'游骑兵'#flask的第三方模块加到一起甚至比django还多并且也越来越像django#flask由于过多......
  • Django之auth认证模块
    目录前戏:auth模块的使用auth之用户注册auth模块之登录request.user方法介绍request.user.is_authenticatedauth模块之网页首页auth模块之用户登录过直接跳转页面auth模块之用户修改密码auth模块之注销用户auth模块之扩展表前戏:django自带一个admin路由但是需要我们提供管理员......
  • Django面试题
    1.DjangoORM查询中select_related和prefetch_related的区别??defselect_related(self,*fields)性能相关:表之间进行join连表操作,一次性获取关联的数据。总结:1.select_related主要针一对一和多对一关系进行优化。2.select_related使用SQL的JOIN语句进行......