Django 事务操作
如何在Django中进行事务操作
案例:
客户A要给客户B转一笔钱,这个在数据库中需要进行两步:
1.客户A减钱
2.客户B加钱
如果在第一步结束后,服务器出现异常,停下了,第二步没有进行,如果数据库使用了事务操作,真的出现异常的时候,前面的操作会进行回滚。
简单的说就是:要么全部执行成功,要么一个都不执行。
这个回滚的操作就叫做数据库的原子性操作。
但是,这是在MySQL数据库中,而我们在Django的ORM中如何进行呢?
显式控制事务
Django提供了一个API来控制数据库事务。
atomic(using = None,savepoint = 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_commit(sid,using = None)
-
提交保存点sid。自创建保存点以来执行的更改将成为事务的一部分。
- 3)savepoint_rollback(sid,using = 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_rollback(using = None)
set_rollback(rollback,using = None)
设置回滚标志以True在退出最内层原子块时强制回滚。这可能有助于在不引发异常的情况下触发回滚。
将其设置为False阻止此类回滚。在此之前,请确保您已将事务回滚到当前原子块中的已知良好保存点!否则,您将破坏原子性并可能发生数据损坏。
至此。转载请注明出处。
[ 本站相关链接:>>Django部署 ]
Django 事务操作的更多相关文章
- Django的ORM实现数据库事务操作
在Django中实现数据库的事务操作 在学习MySQL数据库时,MySQL数据库是支持原子操作的. 什么是数据库的原子操作呢??打个比方,一个消费者在一个商户里刷信用卡消费. 交易正常时,银行在消费者 ...
- Django中-事务操作
如何在Django中进行事务操作呢? 近期,公司里要使用Django开发一套金融相关的系统. 涉及钱了.....安全安全安全 如果钱转到一半,系统崩了,咋办? 如果钱汇到一半,系统崩了,咋办? 如果东 ...
- django基础之day05,orm字段参数,自定义需要的字段,orm中的事务操作
orm字段和参数 charfield varchar integerfield int bigintegerfield bigint emailfield varchar(254) datefield ...
- Django orm进阶查询(聚合、分组、F查询、Q查询)、常见字段、查询优化及事务操作
Django orm进阶查询(聚合.分组.F查询.Q查询).常见字段.查询优化及事务操作 聚合查询 记住用到关键字aggregate然后还有几个常用的聚合函数就好了 from django.db.mo ...
- Django---Django的ORM的一对多操作(外键操作),ORM的多对多操作(关系管理对象),ORM的分组聚合,ORM的F字段查询和Q字段条件查询,Django的事务操作,额外(Django的终端打印SQL语句,脚本调试)
Django---Django的ORM的一对多操作(外键操作),ORM的多对多操作(关系管理对象),ORM的分组聚合,ORM的F字段查询和Q字段条件查询,Django的事务操作,额外(Django的终 ...
- python 全栈开发,Day118(django事务,闭包,客户管理,教学管理,权限应用)
昨日内容回顾 一.django事务 什么是事务 一系列将要发生或正在发生的连续操作. 作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行. 事务处理可以确保除非事务性单元内的所有操 ...
- python---django中orm的使用(5)数据库的基本操作(性能相关:select_related,和prefetch_related重点)(以及事务操作)
################################################################## # PUBLIC METHODS THAT ALTER ATTRI ...
- Django 事务
Django事务 事务是通过将一组相关操作组合为一个,要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠.事务具有4个特性:原子性.一致性.隔离性.持久性. 默认情况下,在Djang ...
- Django框架10 /sweetalert插件、django事务和锁、中间件、django请求生命周期
Django框架10 /sweetalert插件.django事务和锁.中间件.django请求生命周期 目录 Django框架10 /sweetalert插件.django事务和锁.中间件.djan ...
随机推荐
- [Swift]LeetCode115. 不同的子序列 | Distinct Subsequences
Given a string S and a string T, count the number of distinct subsequences of S which equals T. A su ...
- [Swift]LeetCode251.展平二维向量 $ Flatten 2D Vector
Implement an iterator to flatten a 2d vector. For example,Given 2d vector = [ [1,2], [3], [4,5,6] ] ...
- [Swift]LeetCode438. 找到字符串中所有字母异位词 | Find All Anagrams in a String
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings ...
- 使用(POI)SAX处理Excel大文件,防止内存溢出
POISAXReader h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-chi ...
- 初步学习大数据——设置虚拟机固定ip地址
1.打开本机的网络连接 2.右键以太网,打开属性. 3.右键VMnet8,打开属性.最多不能超过255,最少不能小于0. 0~255之间. 4.找到你要设置固定IP地址的虚拟机 ,选择上方的编辑 ...
- Linux中FTP远程传输,SSH远程连接,以及SCP远程拷贝
常用服务器ftp.ssh 1. Linux常用服务器构建-ftp服务器 ftp服务器 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”. 用于 ...
- scala读取配置文件
Class: package libparser import scala.collection.mutable import scala.util.matching.Regex class conf ...
- Python内置函数(53)——repr
英文文档: repr(object) Return a string containing a printable representation of an object. For many type ...
- java基础(十二 )-----Java泛型详解
本文对java的泛型的概念和使用做了详尽的介绍. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即“参数化类型”.一提到 ...
- 初探Java设计模式3:行为型模式(策略,观察者等)
行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰. 策略模式 策略模式太常用了,所以把它放到最前面进行介绍.它比较简单,我就不废话,直接用代码说事吧. 下面 ...