数据库的读写操作中,事务在保证数据的安全性和一致性方面起着关键的作用,而回滚正是这里面的核心操作。Django的ORM在事务方面也提供了不少的API。有事务出错的整体回滚操作,也有基于保存点的部分回滚。本文将讨论Django中的这两种机制的运行原理。

Django利用django.db.transaction模块中的API对数据库进行事务的管理

Django provides a straightforward API in the django.db.transaction module to manage the autocommit state of each database connection.

主要函数:

1. get_autocommit(using=None)

判断事务是否自动提交

2. set_autocommit(autocommit, using=None)

设置自动提交事务

这些函数使接受一个 using 参数表示所要操作的数据库。如果未提供,则 Django 使用 "default" 数据库。

 

3. on_commit(do something)

事务提交后马上执行任务,例如celery任务

例如:

with transation.atomic:

#do something and commit the transaction

transaction.on_commit(lambda: some_celery_task.delay('arg1'))

怎么使用?在哪里使用?

事务是一系列的数据库操作,在数据的安全性和减少网络请求方面都有很大的优势。关于数据库事务的文章有很多,我这里就不展开讨论了。

那么ORM中有哪些相关的API呢?

trasation模块中最重要的是一个Atomic类,Atomic是一个上下文管理器。可以使用@transaction.atomic 或者with transaction.atomic 的方式来调用。

为了设置保存点,即断点进行事务的执行和回滚,可以嵌套使用with transaction.atomic,例如官网的例子(伪代码):

  1. with transaction.atomic(): # Outer atomic, start a new transaction
  2. transaction.on_commit(foo) #事务提交后马上执行foo函数
  3.  
  4. try:
  5. with transaction.atomic(): # Inner atomic block, create a savepoint
  6. transaction.on_commit(bar) #事务提交后马上执行foo函数
  7. raise SomeError() # Raising an exception - abort the savepoint
  8. except SomeError:
  9. pass

第一个with transaction.atomic()创建事务,第二个with transaction.atomic()创建保存点。

虽然错误raiseSomeError是从‘内部’的保存点发出来的,但只会影响到‘外部’的保存点,即只会回滚前面的数据库操作。

下面还会讨论另一种创建保存点的方法。

在使用transaction.atomic前需要注意的问题:

1. 数据库的自动提交默认为开启,如果要将它关闭,必须很小心。一旦使用了transaction,即关闭了自动提交。

2. 如果数据库之前的使用的是自动提交,那么在切换为非自动提交之前,必须确保当前没有活动的事务,通常可以手动执行commit() 或者 rollback() 函数来把未提交的事务提交或者回滚。

一、整体回滚

所有的数据库更新操作都会在一个事务中执行,如果事务中任何一个环节出现错误,都会回滚整个事务。

案例(伪代码1):

  1. from django.db import transaction
  2.  
  3. # open a transaction
  4. @transaction.atomic #装饰器格式
  5. def func_views(request):
  6. do_something()
  7. a = A() #实例化数据库模型
  8. try:
  9. a.save()
  10. except DatabaseError:
  11. pass

此方案整个view都会在事务之中,所有对数据库的操作都是原子性的。

案例(伪代码2):

  1. from django.db import transaction
  2.  
  3. def func_views(request):
  4. try:
  5. with transaction.atomic(): #上下文格式,可以在python代码的任何位置使用
  6. a = A()
  7. a.save()
  8. #raise DatabaseError #测试用,检测是否能捕捉错误
  9. except DatabaseError: # 自动回滚,不需要任何操作
  10. pass

此方案比较灵活,事务可以在代码中的任意地方开启,对于事务开启前的数据库操作是必定会执行的,事务开启后的数据库操作一旦出现错误就会回滚。

需要注意的是:

1. python代码中对Models的修改和对数据库的修改的区别,数据库层面的修改不会影响Models实例变量。

如果在代码中修改一个变量,例如:

  1. try:
  2. with transaction.atomic():
  3. a = A()
  4. a.attribute = True #A表的某一个属性(即数据库的某一列)
  5. a.save()
  6. raise DatabaseError
  7. except DatabaseError:
  8. pass
  9.  
  10. print(a.attribute)

#输出结果:True

即使数据库回滚了,但是a实例的变量a.attribute还是会保存在Models实例中,如果需要修改,就需要在except DatabaseError后面进行。

2. transaction不需要在代码中手动commit和rollback的。因为只有当一个transaction正常退出的时候,才会对数据库层面进行操作。除非我们手动调用transaction.commit和transaction.rollback

实际案例(此实例用伪代码2的格式):

models.py

数据表

  1. class Author(models.Model):
  2. name = models.CharField(max_length=30,null=False)
  3. age = models.IntegerField()
  4. email = models.URLField(null=True)
  5.  
  6. class Count(models.Model):
  7. name = models.CharField(max_length=30)
  8. article_amount = models.IntegerField()

views.py

  1. from django.shortcuts import render
  2. from django.http import HttpResponse
  3. from index.models import Author,Count
  4. from django.db import transaction,IntegrityError
  5.  
  6. def add_author_views(request):
  7. author_name = u'renyingying'
  8. author = Author(name=author_name, age=24, email='renyingying@qqq.com')
  9. # author.save()
  10.  
  11. count = Count(name=author_name, article_amount=1)
  12. count.save()
  13.  
  14. try:
  15. with transaction.atomic():
  16. author.save()
  17. raise DatabaseError #报出错误,检测事务是否能捕捉错误
  18. except DatabaseError: # 自动回滚,不需要任何操作
  19. pass

事务外的数据库操作正常执行,而事务内的数据库操作则会回滚。

author表

count表

将raise DatabaseError这一行代码注释掉,author才会有数据

二、保存点Savepoint(断点回滚)

保存点是事务中的标记,从原理实现上来说是一个类似存储结构的类。可以回滚部分事务,而不是完整事务,同时会保存部分事务。python后端程序可以使用保存点。

一旦打开事务atomic(),就会构建一系列等待提交或回滚的数据库操作。通常,如果发出回滚命令,则会回滚整个事务。保存点则提供了执行细粒度回滚的功能,而不是将执行的完全回滚transaction.rollback()。

工作原理:savepoint通过对返回sid后面的将要执行的数据库操作进行计数,并保存在内置的列表中,当对数据库数据库进行操作时遇到错误而中断,根据sid寻找之前的保存点并回滚数据,并将这个操作从列表中删除。

相关API:

1. savepoint(using = None)

创建一个新的保存点。这表示处于正常状态的事务的一个点。返回保存点ID(sid)。在一个事务中可以创建多个保存点。

2. savepoint_commit(sid,using = None)

发布保存点sid,从创建保存点开始执行的数据库操作将成为可能回滚事务的一部分

3. savepoint_rollback(sid,using = None)

将事务回滚到保存点sid

4. clean_savepoints(using = None)

重置用于生成唯一保存点ID的计数器

值得注意的是:

这些函数中的每一个都接受一个using参数,该参数是数据库的名称。如果using未提供参数,则使用"default"默认数据库。

案例:

models.py上文的案例一样

views.py

  1. from django.db import transaction
  2.  
  3. # open a transaction
  4. @transaction.atomic
  5. def add_author_views(request):
  6. # 自动提交方式
  7. # Author.objects.create(name=u'wangbaoqiang',age=33,email='wangbaoqiang@qqq.com')
  8.  
  9. author_name = u'linghuchong'
  10. author = Author(name=author_name,age=26,email='linghuchong@qqq.com')
  11. author.save()
  12. # transaction now contains author.save()
  13.  
  14. sid = transaction.savepoint()
  15.  
  16. try:
  17. count = Count(name=author_name, article_amount=1)
  18. count.save()
  19. # transaction now contains author.save() and count.save()
  20. transaction.savepoint_commit(sid)
  21. # open transaction still contains author.save() and count.save()
  22. except IntegrityError:
  23. transaction.savepoint_rollback(sid)
  24. # open transaction now contains only count.save()
  25. # 保存author操作回滚后,事务只剩下一个操作
  26.  
  27. transaction.clean_savepoints() #清除保存点

注意:希望当遇到错误得到回滚的事务一定要放在try里面(如果放在try外面,虽然不会报错,但是是不会执行的)。如上面的例子,如果在给Count表执行插入数据发生错误,就会‘断点’回滚到Count表插入数据前,Author表插入的数据不变。

结果显示:

Author表

Count表

参考文章:

https://blog.csdn.net/m0_37422289/article/details/82221489

Django数据库--事务及事务回滚的更多相关文章

  1. SSM保姆级从创建项目到使用,包括事务和设置回滚

    1. 简介 Spring 和 Mybaits整合 2. 创建项目 负责将代理类记性扫描,扫描的是Mapper接口所在的包,这个是mybatis提供的,所以会去找SqlSessionFactory 2. ...

  2. Spring事务控制和回滚

    1在一个项目中ssh结构,spring2.5,事务控制采用的是tx拦截器的方式. 自己写了个 int a=1/0;异常抛出了,但是事务还是提交了,怎么搞都不行. 现将看到的一些事务控制总结下来: 事务 ...

  3. NESTED内部事务异常会回滚 外部事务不会回滚 ;内部事务没有异常,外部事务有异常 则整体事务都回滚

    NESTED内部事务异常会回滚 外部事务不会回滚 :内部事务没有异常,外部事务有异常 则整体事务都回滚

  4. nestd事务如果报错了 则回滚到外部事物保存点 且外部事物如果没异常的话 会正常提交 nested事务并不会提交;如果外部事物报错了 内部事务会一同回滚

    nestd事务如果报错了 则回滚到外部事物保存点 且外部事物如果没异常的话 会正常提交 nested事务并不会提交:如果外部事物报错了 内部事务会一同回滚

  5. 【转】批量复制操作(SqlBulkCopy)的出错处理:事务提交、回滚

    原文地址:http://blog.csdn.net/westsource/article/details/6658109 默认情况下,批量复制操作作为独立的操作执行. 批量复制操作以非事务性方式发生, ...

  6. 关于SAP的事务提交和回滚(LUW)

    1 Sap的更新的类型 在sap中,可以使用CALL FUNCTION ... IN UPDATE TASK将多个数据更新绑定到一个database LUW中.程序使用COMMIT WORK提交修改请 ...

  7. 对mysql事务提交、回滚的错误理解

    一.起因 begin或者START TRANSACTION开始一个事务 rollback事务回滚 commit 事务确认 人们对事务的解释如下:事务由作为一个单独单元的一个或多个SQL语句组成,如果其 ...

  8. Spring事务超时、回滚的相关说明

    事务超时: @Transactional(timeout = 60) 如果用这个注解描述一个方法的话,线程已经跑到方法里面,如果已经过去60秒了还没跑完这个方法并且线程在这个方法中的后面还有涉及到对数 ...

  9. JDBC03 利用JDBC实现事务提交与回滚【调用Connection中的方法实现事务管理】

    目录 1 Connection中的重用方法 2 JDBC事务管理经典案例 1 Connection类中常用的方法回顾 1.1 Statement createStatement() throws SQ ...

  10. MySQL事务提交与回滚

    提交 为了演示效果,需要打开两个终端窗口,使用同一个数据库,操作同一张表 step1:连接 终端1:查询商品分类信息 select * from goods_cates; step2:增加数据 终端2 ...

随机推荐

  1. [Swift]LeetCode114. 二叉树展开为链表 | Flatten Binary Tree to Linked List

    Given a binary tree, flatten it to a linked list in-place. For example, given the following tree: 1 ...

  2. [Swift]LeetCode944. 删除列以使之有序 | Delete Columns to Make Sorted

    We are given an array A of N lowercase letter strings, all of the same length. Now, we may choose an ...

  3. Data - Tools

    数据工具汇总 史上最全的大数据分析和制作工具 全球100款大数据工具汇总 SQL 数据分析常用语句 01 - NumPy HomePage:http://www.numpy.org/ NumPy(数值 ...

  4. Python内置函数(58)——slice

    英文文档: class slice(stop) class slice(start, stop[, step]) Return a slice object representing the set ...

  5. 8分钟学会Consul集群搭建及微服务概念

    Consul介绍: Consul 是由 HashiCorp 公司推出的开源软件,用于实现分布式系统的服务发现与配置.与其他分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与 ...

  6. MassTransit&Sagas分布式服务开发ppt分享

    saga,与分布式相关,最早被定义在Hector Garcia-Molina和Kenneth Salem的论文"Sagas"中.这篇论文提出了一个saga机制来作为分布式事务的替代 ...

  7. 【干货】Chrome插件(扩展)开发全攻略

    写在前面 我花了将近一个多月的时间断断续续写下这篇博文,并精心写下完整demo,写博客的辛苦大家懂的,所以转载务必保留出处.本文所有涉及到的大部分代码均在这个demo里面:https://github ...

  8. dotnet core高吞吐Http api服务组件FastHttpApi

    简介 是dotNet core下基于Beetlex实现的一个高度精简化和高吞吐的HTTP API服务开源组件,它并没有完全实现HTTP SERVER的所有功能,而是只实现了在APP和WEB中提供数据服 ...

  9. Mongodb~Linux环境下的部署~服务的部署与自动化

    <mongodb在linux上的部署> 事实上redis安装程序挺好,直接帮我们生成了服务,直接可以使用systemctl去启动它,而mongodb在这方面没有那么智能,需要我们去编写自己 ...

  10. 在AspNetCore中使用极验做行为认证

    先上效果图 极验的流程 极验官方文档地址 https://docs.geetest.com/install/deploy/server/csharp 简单说明一下极验的验证流程 引用官方的图片 向服务 ...