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装 ...
随机推荐
- [虾扯蛋] android界面框架-Window
从纯sdk及framwork的角度看,android中界面框架相关的类型有:Window,WindowManager,View等.下面就以这几个类为出发点来概览下安卓开发的"界面架构&quo ...
- 异常处理汇总 ~ 修正果带着你的Net飞奔吧!
经验库开源地址:https://github.com/dunitian/LoTDotNet 异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983 ...
- nginx的使用
1.nginx的下载 解压后文件目录: 2.nginx的常用命令 nginx -s stop 强制关闭 nginx -s quit 安全关闭 nginx -s reload 改变配置文件的时候,重 ...
- JavaScript动画-磁性吸附
▓▓▓▓▓▓ 大致介绍 磁性吸附是以模拟拖拽为基础添加一个拖拽时范围的限定而来的一个效果,如果对模拟拖拽有疑问的同学请移步模拟拖拽. 源代码.效果:点这里 ▓▓▓▓▓▓ 范围限定(可视区) 先来看一个 ...
- 从Vue.js窥探前端行业
近年来前端开发趋势 1.旧浏览器逐渐淘汰,移动端需求增加: 旧浏览器主要指的是IE6-IE8,它是不支持ES5特性的:IE9+.chrome.sarafi.firefox对ES5是完全支持的,移动端大 ...
- css_02之盒模型、渐变
1.框模型:盒模型,①对象实际宽度=左右外边距+左右边框+左右内边距 + width:②对象实际高度=上下外边距+上下边框+上下内边距 + height: 2.外边距:margin:取值:①top(上 ...
- 屌丝giser成长记-大学篇
作为一名屌丝giser的我,刚接触gis专业是2007年的大一,好悲催,当时gis这个专业是被调剂的,我压根都不知道gis为何物,那时候gis冷门的一逼,报名这个专业的寥寥无几.记得那时候得知被调剂到 ...
- 学习C的笔记
[unsigned] 16位系统中一个int能存储的数据的范围为-32768~32767,而unsigned能存储的数据范围则是0~65535.由于在计算机中,整数是以补码形式存放的.根据最高位的不同 ...
- Android 开发一定要看的15个实战项目
前言: 虽说网上有太多的Android课程,但是大多都是视频,有Android在线开发环境的几乎没有,但是对于学习Android的人来说拥有在线的Android开发环境是非常好的,可以随时动手操作学习 ...
- git提交项目到已存在的远程分支
今天想提交项目到github的远程分支上,那个远程分支是之前就创建好的,而我的本地关联分支还没创建. 之前从未用github提交到远程分支过,弄了半个钟,看了几篇博文,终于折腾出来.现在把步骤整理 ...