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]LeetCode705. 设计哈希集合 | Design HashSet
Design a HashSet without using any built-in hash table libraries. To be specific, your design should ...
- [Swift]LeetCode928. 尽量减少恶意软件的传播 II | Minimize Malware Spread II
(This problem is the same as Minimize Malware Spread, with the differences bolded.) In a network of ...
- [Swift]LeetCode971.翻转二叉树以匹配先序遍历 | Flip Binary Tree To Match Preorder Traversal
Given a binary tree with N nodes, each node has a different value from {1, ..., N}. A node in this b ...
- jupyter-notebook后home页面空白问题
jupyter-notebook后home页面空白问题 解决方案1 更换默认的浏览器,选择谷歌浏览器,很多360打不开的页面,更换谷歌后都能有效解决,并且确保是最新版本的google浏览器. 解决 ...
- Shell从入门到精通进阶之二:Shell字符串处理之${}
上一章节讲解了为什么用${}引用变量,${}还有一个重要的功能,就是文本处理,单行文本基本上可以满足你所有需求. 2.1 获取字符串长度 # VAR='hello world!' # echo $VA ...
- 计算机网络通信TCP/IP协议浅析 网络发展简介(二)
本文对计算机网络通信的原理进行简单的介绍 首先从网络协议分层的概念进行介绍,然后对TCP.IP协议族进行了概念讲解,然后对操作系统关于通信抽象模型进行了简单介绍,最后简单描述了socket 分层的 ...
- springmvc 项目完整示例04 整合mybatis mybatis所需要的jar包 mybatis配置文件 sql语句 mybatis应用
百度百科: MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBat ...
- Java提高班(一)Thread详解
一.概述 在开始学习Thread之前,我们先来了解一下 线程和进程之间的关系: 线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位. 线程不能够独立执行,必须依存在应用程序中,由应用程 ...
- 利用Sklearn实现加州房产价格预测,学习运用机器学习的整个流程(包含很多细节注解)
Chapter1_housing_price_predict .caret, .dropup > .btn > .caret { border-top-color: #000 !impor ...
- Perl线程池
Thread::Pool模块提供了Perl解释器线程的线程池,手册:https://metacpan.org/pod/Thread::Pool.