Mysql事务探索及其在Django中的实践(二)
继上一篇《Mysql事务探索及其在Django中的实践(一)》交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升。
首先贴上Django官方文档中关于Database Transaction一章的介绍:https://docs.djangoproject.com/en/1.9/topics/db/transactions/。
在Django中实现事务主要有两种方式:第一种是基于django ORM框架的事务处理,第二种是基于原生地执行SQL语句的transaction处理。
基于django ORM框架的事务处理
默认情况下,django的事务处理是自动提交(auto-commit),即在执行model.save(),model.delete()时,所有的改动会被立即提交,相当于数据库设置了auto commit,没有任何隐藏的rollback。
在网上查了一些资料,了解到django手动配置事务的方式主要有三种:第一种是将一个http request的所有数据库操作包裹在一个transaction中,第二种是通过transaction中间件对http请求的事务拦截,第三种是自己在view中通过装饰器灵活控制事务(我们的平台最后用的就是这一种)。
1.将一个http request的所有数据库操作包裹在一个transaction中
这种方式配置非常简单,只需要在settings.py中的database配置中加入‘ATOMIC_REQUESTS’: True即可。如图1所示:

图1 Database中加入'ATOMIC_REQUESTS':True
通过这种配置,django在调每个view方法之前会开始一个事务,当且仅当该响应没有任何问题,django才会提交这个事务;如果view中出现了异常,则django会回滚该事务。这样做的好处显而易见,就是安全简便,但是随着网站的流量变大,如果每个view被调用时都打开一个事务就会变得有点繁重,从而会降低网站的效率。它对性能的影响取决于你的应用的查询效率以及你的数据库处理锁的能力。此外,使用这种方式,回退的只是数据库的状态,而不包括其他非数据库项的操作,例如发送email等。
2.通过transaction中间件对http请求的事务拦截
配置方法是在settings.py中配置MIDDLEWARE_CLASSES,如图2所示:

图2 transaction中间件配置
需要注意的是,这样配置之后,与你中间件的配置顺序是有很大关系的。在 TransactionMiddleware 之后的所有中间件都会受到事务的控制。但CacheMiddleware,UpdateCacheMiddleware,FetchFromCacheMiddleware 这些中间件不会受到影响,因为cache机制有自己的处理方式,用了内部的connection来处理。另外TransactionMiddleware 只对默认的数据库配置有效,如果要对另外的数据连接用这种方式,必须自己实现中间件。(此处必须声明,对于这种方法,本人没有仔细研究过,只是借鉴了一下网上的资料)
3.自己在view中通过装饰器灵活控制事务
最后种方式,通过装饰器灵活配置,也是我们平台最后采用的方式。
1)@transaction.autocommit
django默认的事务处理,采用此装饰模式这种方式可以忽视全局的transaction配置。
2)@transaction.commit_on_success

采用此装饰模式,当此方法的所有工作完成后,才会提交事务。
3)@transaction.commit_manually

采用这种方式,你可以自由地随意提交或回滚事务,完全自己处理。如果没有调用commit()或rollback(),则程序会抛出TransactionManagementError异常。
基于原生地执行SQL语句的transaction处理
再来讲讲Django中第二种事务处理方式,即用原生地执行SQL语句的方式。

图3 原生地执行SQL语句中的事务处理
这种处理方式比较简单,以图3中的方法为例,首先定义了一个游标cursor,通过cursor任意地执行sql语句,最后通过transaction.commit_unless_managed()来提交事务。
延伸
上面介绍了Django中的两种事务处理的方式,到这里我突然想到一个问题:
如果一个方法中既包含了装饰器@transaction.commit_on_success,又执行了原生SQL语句的事务提交,当方法出现异常导致事务回滚时,原生的SQL语句所提交的事务会不会被回滚?
为了验证这个问题,我用Flask写了两个接口来进行验证:

接口delete_and_insert和接口delete_and_insert2都是先通过cursor事务提交执行清除表,然后往表里循环插入数据,当满足条件i=480的时候,抛出一个ValueError。唯一的区别就是接口1中采用了装饰器@transaction.commit_on_success,而接口2中没有。实际执行发现:
1.在调接口1时,原数据库表中的数据不会变化,说明通过cursor执行清除表的操作也会回滚。
2.在调接口2时,原数据库表中的数据被删除,数据库留下的是新的数据:所有的name都为user,而age从1到480。
从而证明,当view方法加了装饰器@transaction.commit_on_success后,即使view中使用了cursor执行原生sql语句,并执行了transaction.commit_unless_managed(),但是如果view中有异常抛出,整个view方法的内容都会回滚。
实际应用
最后,回归最初的问题本身,当我把事务应用到我们平台的后台接口中后,发现了一个意外的惊喜:接口A的执行时间从原来的5-10分钟一下子缩短到了几秒钟就完成了。欣喜之余仔细思考了一下才觉得性能显著提升的原因应该是:在应用事务之前,所有SQL语句都是自动提交的,每插入一条数据,数据库表的索引可能就需要重建一次,当大量的sql语句逐一插入时,数据库表的索引就需要不断地重建,其中就需要耗费大量的时间。而在应用事务之后,所有的插入是一次性提交,数据库表的索引只需要重建一次,大大减少了开销。
这也验证了数据库的索引不是万能的,合理的建立索引确实能大大地优化查询速度,因为索引的存储结构就像一本字典一样,我们在查找某个特定的字时会根据拼音的首字母的方式先找到该字的第一个字母所在页数,然后直接跳到那一页往后去翻。然而这也决定了字典在初始存储这些字时就需要根据这些字的特点将每个字放在特定的存储位置。当有新的字加入时,为了插入到特定的位置,就必须重新建立映射关系。
补充:合理建立索引
下面是我工作中搜集的一些关于索引建立的规则,也欢迎大家参考,指正:
Mysql事务探索及其在Django中的实践(二)的更多相关文章
- Mysql事务探索及其在Django中的实践(一)
前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...
- 05-雷海林-mysql备份原理与在TDSQL中的实践
05-雷海林-mysql备份原理与在TDSQL中的实践 下载地址: http://files.cnblogs.com/files/MYSQLZOUQI/05-%E9%9B%B7%E6%B5%B7%E6 ...
- Django中模型(二)
Django中模型(二) 三.定义模型 1.模型.属性.表.字段间的关系: 一个模型类在数据库中对应一张表:在模型类中定义的属性,对应该模型对照表中的字段. 2.定义属性 A.概述 ·django根据 ...
- Django 中事务的使用
目录 Django 中事务的使用 Django默认的事务行为 在HTTP请求上加事务 在View中实现事务控制 使用装饰器 使用context manager autocommit() commit_ ...
- python连接redis、redis字符串操作、hash操作、列表操作、其他通用操作、管道、django中使用redis
今日内容概要 python连接redis redis字符串操作 redis之hash操作 redis之列表操作 redis其他 通用操作,管道 django中使用redis 内容详细 1.python ...
- mysql事务隔离分析
首先说明下,这里主要内容为整理总结网络搜索的零散信息. 写在最前面,mysql事务是在Innodb引擎中得以实现的,如果这点不了解的话,请自行了解. 事务直接数据的可见性通过MVCC(多版本并发控制) ...
- django中使用mysql数据库的事务
django中怎么使用mysql数据库的事务 Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起 ...
- django中怎么使用mysql数据库的事务
Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败. Django中对于数据库的事务,默认每执行 ...
- 事务的隔离级别,mysql中开启事务、django中开启事务
目录 一.事务的特性 二.数据库中开启事务 三.Django中开启事务的两种方式 第一种 第二种 四.事务的隔离级别 隔离级别 如何查看mysql隔离级别? 修改事务的隔离级别 隔离级别解释 read ...
随机推荐
- 读书笔记:JavaScript DOM 编程艺术(第二版)
读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...
- Windows Server 2012 NIC Teaming介绍及注意事项
Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(69)-微信公众平台开发-功能概述
系列目录 为什么要先发这个文章? 因为接下来的文章是关于微信开发的系列,心中一定要有一个概念,知道自己接下来要做什么功能. 而且微信到处都是坑,我首先要把微信与本地跑通起来才敢发布,否则中间出现坑导致 ...
- 苹果强制使用HTTPS传输了怎么办?——关于HTTPS,APP开发者必须知道的事
WeTest 导读 2017年1月1日起,苹果公司将强制使用HTTPS协议传输.本文通过对HTTPS基础原理和通信过程内容的讲解,介绍APP开发者在这个背景下的应对办法. 几周前,我们在<htt ...
- C#多线程之基础篇3
在上一篇C#多线程之基础篇2中,我们主要讲述了确定线程的状态.线程优先级.前台线程和后台线程以及向线程传递参数的知识,在这一篇中我们将讲述如何使用C#的lock关键字锁定线程.使用Monitor锁定线 ...
- canvas与html5实现视频截图功能
这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...
- ZKWeb网页框架1.3正式发布
本次更新的内容有 更新引用包版本 Microsoft.AspNetCore.Hosting.Abstractions 1.1.0 Microsoft.AspNetCore.Http.Abstracti ...
- 【深入Java虚拟机】之四:类加载机制
类加载过程 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 其中类加载的过程包括了加载.验 ...
- 记一次.NET代码重构
好久没写代码了,终于好不容易接到了开发任务,一看时间还挺充足的,我就慢慢整吧,若是遇上赶进度,基本上直接是功能优先,完全不考虑设计.你可以认为我完全没有追求,当身后有鞭子使劲赶的时候,神马设计都是浮云 ...
- Android—基于GifView显示gif动态图片
android中显示gif动态图片用到了开源框架GifView 1.拷GifView.jar到自己的项目中. 2.将自己的gif图片拷贝到drawable文件夹 3.在xml文件中设置基本属性: &l ...