Mysql事务探索及其在Django中的实践(一)
前言
很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结、沉淀,方便以后对过去的知识进行梳理、追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友。所幸近期通过了博客园的申请,那么今天就开始第一篇随笔,来开始记录自己的学习点滴。
问题背景
本人最近在用python的Web开发框架Django开发一个平台,平台的数据库用的是远程的Mysql (RDS),出于对数据库信息的安全考虑,对访问数据库的ip作了限制。因此,我们是通过在服务器上用轻量级的python Web框架Flask搭建了一些数据存取接口,所有外部机子对数据库的访问是通过调用接口来实现的。而我们起这个web接口的方式非常简单,没有通过任何的容器,仅仅是使用 “python qvServer.py”的方式(qvServer.py是我们的python接口脚本)。这种起接口的方式会存在一个严重的问题:
问题1 单线程:当Flask在处理某一个请求时,如果该请求还没有处理完成,而其他的应用程序又发送了新的请求,此时新请求需要等待,直到前一个请求处理完成时服务器才可以开始处理下一个请求。
当然,这样起也有好处:所有请求排队进行等候一一处理,不会有多个接口同时被调用,而同时对数据库表进行并行操作的风险。然后,在实际执行过程中,我们发现有一些接口的执行时间非常长,比如接口A在执行时,需要执行几千条的SQL插入命令,可能需要耗费将近5-10分钟的时间。此时将会导致其他请求严重阻塞!
为了解决这个问题,参考了朋友的意见和书《Python Web测试驱动方法》中的内容,决定采用Python的容器gunicorn(Green Unicorn,俗称“绿色独角兽”)通过多个进程来起Flask接口服务。使用gunicorn起web服务的命令很简单:nohup gunicorn -w 4 -b 0.0.0.0:9001 qvServer:app & 之后我们查看linux进程的状态,如下图1所示:

图1 查看gunicorn进程
可以看到gunicorn是通过5个进程,一个父进程(PID:17135)和四个子进程来起qvServer,这样处理后,通过实际的执行验证,确实解决了请求不能并发处理的问题,服务器可以同时支持多个请求并行处理,处理效率大大提升,但是却出现了另一个新的问题:
问题2 并发处理导致数据存储失败:还是那个接口A,几千条SQL插入命令在处理时,总是执行失败,且最终数据库总是会残留一部分的脏数据(部分插入成功,发生失败后后续插入操作被中断)
为了解决脏数据的问题,我们自然而然(其实是在老大的提醒下)地会想到引入数据库事务来管理请求,当发生异常时,将这一次的所有数据进行回滚,杜绝脏数据残留在数据库中。由于本人之前对这一块毫无所知,所以趁着清明假期特地学习了一下,主要是借鉴了《深入浅出MySQL——数据库开发、优化与管理维护》一书,下面就是对数据库事务的一些总结,以及在Django中的使用。
事务基础
个人的理解:“事务”就是对一系列与数据库相关操作的封装。主要是当你在对数据库进行“写”操作时,你可以将一系列的操作进行“捆绑”,当且仅当所有这一系列操作都执行成功时,你再进行“一次提交”通知Mysql进行一次性地处理。如果中间的某一项操作出现了异常,你可以对整个事务包含的所有操作(包括已经成功的操作)进行“回滚”,回到执行前的状态。此外,你可以在你的这一系列操作中间设置“保存点”(savepoint),当出现异常时,你可以选择回滚到指定保存点,使得该保存点之前的所有操作执行有效,该保存点后的所有操作都被回退。
默认情况下,Mysql的事务是自动提交的,即你每执行一条sql语句,都会立即提交到数据库。
下面是事务的一些基本操作:
start transaction —— 开始事务
commit —— 提交事务
commit and chain —— 提交事务,并启动一个新的事务
rollback —— 回滚事务(默认回滚整个事务)
savepoint test —— 定义savepoint,名为test (注意:mysql支持指定回滚事务的一个部分,但是不能指定提交事务的一个部分;复杂的应用可以通过定义多个不同的savepoint,满足不同的条件回滚到不同的savepoint;但是,如果定义了相同名字的savepoint,则后面定义的会覆盖前面定义的!)
rollback to savepoint test —— 回滚到savepoint test处
release savepoint test —— 删除名为test的savepoint
下面是一些实际的操作:
1. 事务开始和提交。
首先通过cmd命令行打开两个数据库连接(session1、session2),初始时表lists_userinfo为空。
步骤1:session1中执行操作:开始事务--插入1行数据--查询

图2 事务开始和提交(1)
步骤2:session2中执行操作:查询

图3 事务开始和提交(2)
可以看到,此时session1中开始了事务,且并未提交,session2中并未查询到任何结果,而session1可以查询到自己已经提交的数据。
步骤3:session1中执行操作:提交事务--查询

图4 事务开始和提交(3)
步骤4:session2中执行操作:查询

图5 事务开始和提交(4)
可以看到,此时session2中才可以查询到session1插入的数据。即:只有当事务完成提交后,事务中的操作才会真正应用到数据库中。
2. 事务回滚。
步骤1:session1执行操作:开始事务--插入1行数据--查询--回滚--查询

图6 事务回滚(1)
可以看到,在rollback后,事务的操作被回滚,实际并没有应用到Mysql中生效。
3. 回滚到指定savepoint及删除指定savepoint。
步骤1:session1执行操作:开始事务--插入1行数据--设置savepoint--再插入1行数据--查询--回滚到savepoint

图7 回滚到指定savepoint及删除指定savepoint(1)
可以看到,当回滚到指定保存点cy后,在保存点cy之后插入的数据没有提交到数据库。那么此时,在session2中进行查询会是什么结果呢?我们来看看步骤2。
步骤2: session2执行操作:查询

图8 回滚到指定savepoint及删除指定savepoint(2)
可以看到此时session2中并没有查询到session1中插入的数据。
步骤3: session1执行操作:提交

图9 回滚到指定savepoint及删除指定savepoint(3)
步骤4: session2执行操作:查询

图10 回滚到指定savepoint及删除指定savepoint(4)
可以看到,即使rollback后,也需要执行commit操作,数据库的事务才能应用生效。
对于删除savepoint,大家可以自己尝试验证一下。步骤如下:

图11 回滚到指定savepoint及删除指定savepoint(5)
可以看到,当删除了savepoint后,系统就找不到指定的savepoint了。
延伸
另外,作为一个Mysql菜鸟,在实践过程中还发现以下两点跟锁相关的事务特性:
1.rollback不能回滚锁。
2.start transaction开启新事务,会自动执行一个隐含的unlock tables操作。
步骤1:session1执行操作: 对表加write锁--插入1行数据

图12 事务与锁(1)
步骤2:session2执行操作:查询

图13 事务与锁(2)
此时session2的查询处于阻塞状态。
步骤3:session1执行操作:start transaction

图14 事务与锁(3)
步骤4:察看session2中之前的”查询“语句执行结果

图15 事务与锁(4)
可以看到,此时session2中的查询执行成功,说明session1中执行start transaction会隐含地将write锁释放。
Mysql事务探索及其在Django中的实践(一)的更多相关文章
- Mysql事务探索及其在Django中的实践(二)
继上一篇<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 中事务的使用 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 ...
- Django中MySQL事务的使用
Django中事物的使用 from django.db import transaction @transaction.atomic通过transaction的@transaction.atomic装 ...
随机推荐
- js-静态、原型、实例属性
本篇来说一下js中的属性: 1.静态属性 2.原型属性 3.实例属性 静态属性: function klass(){} var obj=new klass(); klass.count=0; klas ...
- 简谈百度坐标反转至WGS84的三种思路
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 基于百度地图进行数据展示是目前项目中常见场景,但是因为百度地图 ...
- Pivot 和 Unpivot
在TSQL中,使用Pivot和Unpivot运算符将一个关系表转换成另外一个关系表,两个命令实现的操作是“相反”的,但是,pivot之后,不能通过unpivot将数据还原.这两个运算符的操作数比较复杂 ...
- Android 自定义 attr
好纠结,弄了一个下午老是报错如是总结一下安卓自定视图和自定义属性. (一)自定义属性 在Values文件下建立一个attrs.xml文件,attr的format可以参考:http://www.cnbl ...
- 更愉快的书写CSS
我在写CSS的时候经常会碰到些麻烦事儿: 1)看上去蛮简单的排版却写了很久 2)代码写的越来越散,总是这里补一句,那里补一句,没有条理性 3)margin.padding.font-size等属性在不 ...
- Kooboo CMS技术文档之四:Kooboo CMS的站点组成部分
Kooboo CMS本着功能独立分离的原则,将站点分为三部分组成:用户管理,站点管理和内容数据库管理.各个功能之间既可独立使用,也可以容易组成在一起形成一个完整的系统. 用户管理 管理整个系统内的用户 ...
- java中if和switch哪个效率快
首先要看一个问题,if 语句适用范围比较广,只要是 boolean 表达式都可以用 if 判断:而 switch 只能对基本类型进行数值比较.两者的可比性就仅限在两个基本类型比较的范围内.说到基本类型 ...
- es6小白学习笔记(一)
1.let和const命令 1.es6新增了let和const命令,与var用法类似,但它声明的变量只在let所在的代码块内有效(块级作用域,es5只有全局和函数作用域) { let a = 1; v ...
- 初识git版本控制系统
当下git分布式版本控制系统越来越火,掌握git也是必须的一个技能.因此,对git做了如下学习. Git初级指南 1. 先安装git.(ps:在select cmponents处要勾选Git Bash ...
- linux的top命令参数详解
简介 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器. top显示系统当前的进程和其他状况,是一个动态显示过程,即可以通过用户按 ...