继上一篇《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语句逐一插入时,数据库表的索引就需要不断地重建,其中就需要耗费大量的时间。而在应用事务之后,所有的插入是一次性提交,数据库表的索引只需要重建一次,大大减少了开销。

  这也验证了数据库的索引不是万能的,合理的建立索引确实能大大地优化查询速度,因为索引的存储结构就像一本字典一样,我们在查找某个特定的字时会根据拼音的首字母的方式先找到该字的第一个字母所在页数,然后直接跳到那一页往后去翻。然而这也决定了字典在初始存储这些字时就需要根据这些字的特点将每个字放在特定的存储位置。当有新的字加入时,为了插入到特定的位置,就必须重新建立映射关系。

补充:合理建立索引

  下面是我工作中搜集的一些关于索引建立的规则,也欢迎大家参考,指正:

1.搜索的索引列 
最适合索引的列是出现在where子句种的列,或连接子句中指定的列。 而不是select关键字后的选择列表的列。
2.使用唯一索引
索引的列的基数越大,索引效果越好。比如id每行都不同,出生日期也不太相同,适合作索引。 而性别男或女只有两者情况,即使加索引,不管搜索哪个值都会得出大约一半的行。
3.使用短索引 
例如对字符串列进行索引,应该制定一个前缀长度。比如一个CHAR(200)的列,如果前10或20个字符内就大不相同,则可以只对前10个或20个字符进行索引。节省大量索引空间,也使查询更快,涉及的磁盘IO较少。较短的键值,索引高速缓存中的块能容纳更多的键值。
4.不要过度索引
每个额外的索引都要占用额外的磁盘空间,降低写操作的性能。因为在写修改表的内容时,索引必须进行更新,有时可能需要重构。 就比如一本字典,加入新的字必须要根据目录插入指定位置,后面的内容都要更新。
5. 选择最常作为访问条件的列作为主键
InnoDB有一个默认的保存顺序,按照主键或内部列进行访问的速度是最快的(比唯一索引还要快)。

         

  

转载于:https://www.cnblogs.com/znicy/p/5434829.html

Mysql事务探索及其在Django中的实践(二)相关推荐

  1. 05-雷海林-mysql备份原理与在TDSQL中的实践

    05-雷海林-mysql备份原理与在TDSQL中的实践 F F F F F F F F F F F F F F F F F F F F F F F F F F F 下载地址: http://files ...

  2. mysql 事务隔离详解_MySQL 中事务、事务隔离级别详解

    一.事务的概念 1.事务的概念 2.在mysql中哪些存储引擎(表类型)支持事务哪些不支持 3.事务的四个属性 4.mysql事务的创建与存在周期 5.mysql行为 6.事务的隔离性和性能 7.my ...

  3. mysql 事务 注意 优化_MySQL入门详解(二)---mysql事务、锁、以及优化

    MySQL 事务主要用于处理操作量大,复杂度高的数据.比如说,在一个商城系统中,用户执行购买操作,那么用户订单中应该加一条,库存要减一条,如果这两步由于意外只进行了其中一步那么就会发生很大的问题.而事 ...

  4. 完整电商项目--(八)商品订单模块(1):订单结算与 mysql事务

    文章目录 订单结算页面 重点:提交订单 创建订单数据表 注意事项: 订单表介绍 提交订单数据: 保存订单中的数据处理操作(业务逻辑复杂,代码不难,前面都写过) 首先是数据验证和加载 接着是具体得 业务 ...

  5. Mysql事务字符集

    Mysql事务 Innodb存储引擎的中的事务完全服务ACID: 原子性.2.一致性.3.隔离性.4.持久性 理解上和oracle类似. 事务隔离级别 1.Read uncommitted 读未提交: ...

  6. django使用mysql事务处理_Django中MySQL事务的使用

    Django中事物的使用 from django.db import transaction @transaction.atomic 通过transaction的@transaction.atomic ...

  7. django 中的聚合和分组 F查询 Q查询 事务cookies和sessions 066

    django 中的聚合和分组 F查询 Q查询 事务cookies和sessions 066 1 聚合和分组 聚合:对一些数据进行整理分析 进而得到结果(mysql中的聚合函数) 1aggregate( ...

  8. 【Django 天天生鲜项目05】订单(Mysql事务、并发处理、支付宝支付、评论)

    本部分涉及订单的生成.并发处理.支付.评论等 关键:MySQL事务.并发处理的悲观锁/乐观锁.支付宝SDK 的使用...... 仅作为个人笔记! 目录 2.创建订单 3.订单生成 3.1. MySQL ...

  9. Mysql 事务中Update 会锁表吗?

    Mysql 事务中Update 会锁表吗? 两种情况: 1.带索引 2.不带索引 前提介绍: 方式:采用命令行的方式来模拟 1.mysq由于默认是开启自动提交事务,所以首先得查看自己当前的数据库是否开 ...

最新文章

  1. TensorFlow练习9: 生成妹子图(PixelCNN)
  2. 有的OUTLOOK不能自动加载归档ARCHIVE邮件的问题
  3. 【Android】4.3 屏幕布局和旋转
  4. 反序列化的时候出现eof exception_FastJson序列化时候出现了$ref?还不赶紧学习下...
  5. 9 MM配置-主数据-维护物料管理的公司代码
  6. C语言 VS输入输出字符设置
  7. 遍历字典时用与不用iter的区别
  8. jmeter安装和使用-个人总结
  9. Cadence软件包集成了那么多软件,傻傻分不清?
  10. Git-储藏(Stashing)
  11. 仿爱奇艺加载dialog
  12. 机器学习 - 人脸识别
  13. 《恒盛策略》外资巨头突然出手!又有炒股软件罢工
  14. 工单服务管理系统开发
  15. IMU 无线姿态传感器-LPMS-B2系列
  16. MySQL8.0安装与基于二进制日志文件位置的主从复制
  17. win10关闭了微软服务器,win10自带安全软件怎么关闭|win10关闭自带杀毒软件的两种方法...
  18. 电脑技巧:分享6个实用的资源网站
  19. 脉冲消融(PFA)中使用心电门控的作用
  20. 如何在网上调研某公司背景及项目情况

热门文章

  1. ADO.NET与Sql Server和Access的连接
  2. 得到当前选中行的第几列的值---dataGridView
  3. C#写Windows系统日志(EventLog)
  4. 1024x1024 分辨率,效果惊人!InsetGAN:全身图像生成 (CVPR 2022)
  5. CVPR2022 做语义分割不用任何像素标签,UCSD、英伟达在ViT中加入分组模块
  6. 速度最快250fps!实时、高性能车道线检测算法LaneATT
  7. ECCV 2020 谷歌论文盘点—Poster 篇
  8. 令人惊讶的手机端实时 4K 风格迁移!谷歌又出牛文
  9. 我爱计算机视觉干货集锦分类汇总(2019年3月9日)
  10. 干货!286页李宏毅《深度学习讲义》