如何在Django中进行事务操作

案例:

客户A要给客户B转一笔钱,这个在数据库中需要进行两步:

  1.客户A减钱

  2.客户B加钱

如果在第一步结束后,服务器出现异常,停下了,第二步没有进行,如果数据库使用了事务操作,真的出现异常的时候,前面的操作会进行回滚。

简单的说就是:要么全部执行成功,要么一个都不执行。

这个回滚的操作就叫做数据库的原子性操作。

但是,这是在MySQL数据库中,而我们在Django的ORM中如何进行呢?

显式控制事务

Django提供了一个API来控制数据库事务。

atomic(using = Nonesavepoint = True

原子性是数据库事务的定义属性。atomic 允许我们创建一个代码块,在该代码块中保证数据库的原子性。如果代码块成功完成,则更改将提交到数据库。如果存在异常,则回滚更改。


首先,我们要导入一个Django的内置模块

from django.db import transaction

接着,就可以使用了

from django.db import transaction

with transaction.atomic():
# ORM操作
pass

我们举个例子测试一下

方式一

在"try/except"块中开启事务(且用到with上下文管理器)

1.创建一个项目,新建一个APP(基础操作,这里不再赘述);

2.通过ORM创建生成表:

from django.db import models

class UserInfo(models.Model):
username = models.CharField("用户",max_length=32)
balance = models.CharField("余额",max_length=32)

注意啊:踩过的坑,涉及金融计算,涉及小数啊,要求特别精确的,我们用字符串存储。

如果是金融计算的话,我们用一个Decimal来进行计算。

3.我们给数据库加两条数据,用来模拟两个用户之间的转账;

4.配置URL;

5.创建对应的视图函数:

from django.shortcuts import render,HttpResponse
from app01 import models
from django.db import transaction
from django.db.models import F def index(request):
try:
with transaction.atomic():
models.UserInfo.object.filter(id=1).update(balance=F("balance")-100)
models.UserInfo.object.filter(id=2).update(balance=F("balance")+100)
except Exception as e:
return HttpResponse("出现错误<%s>"%str(e))
return HttpResponse("执行成功")

当我们访问index的时候,会进行一次转账操作。

6.现在,我们让他报错:

from django.shortcuts import render,HttpResponse
from app01 import models
from django.db import transaction
from django.db.models import F def index(request):
try:
with transaction.atomic():
models.UserInfo.object.filter(id=1).update(balance=F("balance")-100)
raise '一个错误'
models.UserInfo.object.filter(id=2).update(balance=F("balance")+100)
except Exception as e:
return HttpResponse("出现错误<%s>"%str(e))
return HttpResponse("执行成功")

我们再次查看数据库文件,如果没有数据的原子性操作,我们第一条sql执行完报错,那钱肯定是减去了。

但是,我们进行的是原子性的操作,你会发现钱没有减诶。

完美,没毛病

这是常规的一种操作,另外还有一起其他的方式。

方式二

对整个view视图开启事务

from django.db import transaction

@transaction.atomic
def index(request):
# ORM操作
return ....

注意不要在原子块中进行错误捕获!

当退出原子块的时候,Django会去查看它是否正常退出或者是否有异常来确定是否提交或者回滚。

如果你捕获并处理了原子块中的异常,可能会隐藏Django中发生问题的事实。这样可能会造成非预期的行为。

以上,程序中并没有显示调用commit()提交方法和rollback()回滚方法,原因是Django默认设置为自动提交。当然你可以改变这一切,Django为此提供了相关API:get_autocommit(using=None)set_autocommit(autocommit, using=None)

为什么Django使用自动提交

在SQL标准中,每个SQL查询都会启动一个事务,除非一个事务已经处于活动状态。然后必须显式提交或回滚此类事务。

这对应用程序开发人员来说并不总是方便 为了缓解此问题,大多数数据库都提供自动提交模式。启用自动提交并且没有事务处于活动状态时,每个SQL查询都会包含在自己的事务中。换句话说,不仅每个这样的查询都会启动事务,而且事务也会自动提交或回滚,具体取决于查询是否成功。

事务中的保存点

保存点是事务中的标记,使您可以回滚部分事务,而不是完整事务。SQLite(≥3.6.8),PostgreSQL,Oracle和MySQL(使用InnoDB存储引擎时)后端可以使用保存点。其他后端提供了保存点功能,但它们是空操作 - 它们实际上并没有做任何事情。

如果您使用自动提交(Django的默认行为),则保存点不是特别有用。但是,一旦打开事务atomic(),就会构建一系列等待提交或回滚的数据库操作。如果发出回滚,则回滚整个事务。保存点提供了执行细粒度回滚的功能,而不是将执行的完全回滚transaction.rollback()。

当atomic()装饰器嵌套时,它会创建一个保存点以允许部分提交或回滚。强烈建议您使用atomic()而不是下面描述的功能,但它们仍然是公共API的一部分,并且没有计划弃用它们。

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

保存点由以下三个函数控制django.db.transaction:

1)savepoint(using = None

创建一个新的保存点。这标志着已知处于“良好”状态的交易中的一个点。返回保存点ID(sid)。

2)savepoint_commitsidusing = None

提交保存点sid。自创建保存点以来执行的更改将成为事务的一部分。

3)savepoint_rollback(sidusing = None

将事务回滚到保存点sid。

如果不支持保存点或数据库处于自动提交模式,则这些功能不执行任何操作。

另外,还有一个实用功能:

4)clean_savepoints(using = None

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

以下示例演示了保存点的用法:

from django.db import transaction

# open a transaction
@transaction.atomic
def viewfunc(request): a.save()
# transaction now contains a.save() sid = transaction.savepoint() b.save()
# 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()

保存点可用于通过执行部分回滚从数据库错误中恢复。如果你在一个atomic()区块内执行此操作,整个区块仍将被回滚,因为它不知道你已经处理了较低级别的情况!为防止这种情况,您可以使用以下函数控制回滚行为。

get_rollbackusing = None
set_rollbackrollback,using = None

设置回滚标志以True在退出最内层原子块时强制回滚。这可能有助于在不引发异常的情况下触发回滚。

将其设置为False阻止此类回滚。在此之前,请确保您已将事务回滚到当前原子块中的已知良好保存点!否则,您将破坏原子性并可能发生数据损坏。

  至此。转载请注明出处。

本站相关链接:>>Django部署 ]

Django 事务操作的更多相关文章

  1. Django的ORM实现数据库事务操作

    在Django中实现数据库的事务操作 在学习MySQL数据库时,MySQL数据库是支持原子操作的. 什么是数据库的原子操作呢??打个比方,一个消费者在一个商户里刷信用卡消费. 交易正常时,银行在消费者 ...

  2. Django中-事务操作

    如何在Django中进行事务操作呢? 近期,公司里要使用Django开发一套金融相关的系统. 涉及钱了.....安全安全安全 如果钱转到一半,系统崩了,咋办? 如果钱汇到一半,系统崩了,咋办? 如果东 ...

  3. django基础之day05,orm字段参数,自定义需要的字段,orm中的事务操作

    orm字段和参数 charfield varchar integerfield int bigintegerfield bigint emailfield varchar(254) datefield ...

  4. Django orm进阶查询(聚合、分组、F查询、Q查询)、常见字段、查询优化及事务操作

    Django orm进阶查询(聚合.分组.F查询.Q查询).常见字段.查询优化及事务操作 聚合查询 记住用到关键字aggregate然后还有几个常用的聚合函数就好了 from django.db.mo ...

  5. Django---Django的ORM的一对多操作(外键操作),ORM的多对多操作(关系管理对象),ORM的分组聚合,ORM的F字段查询和Q字段条件查询,Django的事务操作,额外(Django的终端打印SQL语句,脚本调试)

    Django---Django的ORM的一对多操作(外键操作),ORM的多对多操作(关系管理对象),ORM的分组聚合,ORM的F字段查询和Q字段条件查询,Django的事务操作,额外(Django的终 ...

  6. python 全栈开发,Day118(django事务,闭包,客户管理,教学管理,权限应用)

    昨日内容回顾 一.django事务 什么是事务 一系列将要发生或正在发生的连续操作. 作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行. 事务处理可以确保除非事务性单元内的所有操 ...

  7. python---django中orm的使用(5)数据库的基本操作(性能相关:select_related,和prefetch_related重点)(以及事务操作)

    ################################################################## # PUBLIC METHODS THAT ALTER ATTRI ...

  8. Django 事务

    Django事务 事务是通过将一组相关操作组合为一个,要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠.事务具有4个特性:原子性.一致性.隔离性.持久性. 默认情况下,在Djang ...

  9. Django框架10 /sweetalert插件、django事务和锁、中间件、django请求生命周期

    Django框架10 /sweetalert插件.django事务和锁.中间件.django请求生命周期 目录 Django框架10 /sweetalert插件.django事务和锁.中间件.djan ...

随机推荐

  1. [Swift]LeetCode345. 反转字符串中的元音字母 | Reverse Vowels of a String

    Write a function that takes a string as input and reverse only the vowels of a string. Example 1: In ...

  2. javascript时间戳与日期格式之间的互转

    1. 将时间戳转换成日期格式 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 /** 1. 下面是获取时间日期的方法,需要什么样的格式自己拼接起来就好了 ...

  3. 还在使用SimpleDateFormat?你的项目崩没?

    如果是在多线程环境下,就需要注意了. 要点: 1.加Synchronized同步: 2.使用ThreadLocal: 3.jdk8使用DateTimeFormatter替代SimpleDateForm ...

  4. mongo 联表查询

    查询语句 db.getCollection("A表").aggregate([ { $lookup:{ from:"B表", localField:" ...

  5. Linux 文件夹压缩命令总结

    tar命令 解包:tar zxvf FileName.tar 打包:tar czvf FileName.tar DirName gz命令 解压1:gunzip FileName.gz 解压2:gzip ...

  6. virtuoso操作graph的方法--查询和删除

    在virtuoso中查看某个graph的数据,直接用sparql语句查询就可以了,对graph进行查询也可以通过sparql实现,删除graph则要在isql中操作. 1 查询graph的命令 在lo ...

  7. SpringCloud(9)---mysql实现配置中心

    mysql实现配置中心 本公司配置数据的管理是通过mysql进行配置管理,因为已经搭建好了,所以自己动手重新搭建一遍,熟悉整个流程.有关项目源码后期会补上github地址 微服务要实现集中管理微服务配 ...

  8. java算法(1)---余弦相似度计算字符串相似率

    余弦相似度计算字符串相似率 功能需求:最近在做通过爬虫技术去爬取各大相关网站的新闻,储存到公司数据中.这里面就有一个技术点,就是如何保证你已爬取的新闻,再有相似的新闻 或者一样的新闻,那就不存储到数据 ...

  9. 经典案例复盘——运维专家讲述如何实现K8S落地

    经典案例复盘——运维专家讲述如何实现K8S落地 背景介绍 运满满自开始微服务改造以来,线上线下已有数千个微服务的 Java 实例在运行中.这些 Java 实例部署在数百台云服务器或虚机上,除少数访问量 ...

  10. 使用ASP.NET MVC Web SignalR 构建单身聊天室(一)

    前言:本系列的头章,想要带大家一起学习Web SignalR,那它是什么呢?ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么 ...