前言 

  很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结、沉淀,方便以后对过去的知识进行梳理、追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友。所幸近期通过了博客园的申请,那么今天就开始第一篇随笔,来开始记录自己的学习点滴。

问题背景

  本人最近在用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中的实践(一)的更多相关文章

  1. Mysql事务探索及其在Django中的实践(二)

    继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...

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

    05-雷海林-mysql备份原理与在TDSQL中的实践 下载地址: http://files.cnblogs.com/files/MYSQLZOUQI/05-%E9%9B%B7%E6%B5%B7%E6 ...

  3. Django 中事务的使用

    目录 Django 中事务的使用 Django默认的事务行为 在HTTP请求上加事务 在View中实现事务控制 使用装饰器 使用context manager autocommit() commit_ ...

  4. python连接redis、redis字符串操作、hash操作、列表操作、其他通用操作、管道、django中使用redis

    今日内容概要 python连接redis redis字符串操作 redis之hash操作 redis之列表操作 redis其他 通用操作,管道 django中使用redis 内容详细 1.python ...

  5. mysql事务隔离分析

    首先说明下,这里主要内容为整理总结网络搜索的零散信息. 写在最前面,mysql事务是在Innodb引擎中得以实现的,如果这点不了解的话,请自行了解. 事务直接数据的可见性通过MVCC(多版本并发控制) ...

  6. django中使用mysql数据库的事务

    django中怎么使用mysql数据库的事务   Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起 ...

  7. django中怎么使用mysql数据库的事务

    Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败. Django中对于数据库的事务,默认每执行 ...

  8. 事务的隔离级别,mysql中开启事务、django中开启事务

    目录 一.事务的特性 二.数据库中开启事务 三.Django中开启事务的两种方式 第一种 第二种 四.事务的隔离级别 隔离级别 如何查看mysql隔离级别? 修改事务的隔离级别 隔离级别解释 read ...

  9. Django中MySQL事务的使用

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

随机推荐

  1. Sublime Text3安装JsHint

    介绍 Sublime Text3使用jshint依赖Nodejs,SublimeLinter和Sublimelinter-jshint. NodeJs的安装省略. 安装SublimeLinter Su ...

  2. 手动添加kdump

    背景:     Linux嵌入式设备内核挂死后,无法自动重启,需要手动重启.而且如果当时没有连串口的话,就无法记录内核挂死时的堆栈,所以需要添加一种方式来记录内核挂死信息方便以后调试使用.设备中增加k ...

  3. js闭包for循环总是只执行最后一个值得解决方法

    <style> li{ list-style: none;width:40px;height: 40px;text-align:center;line-height: 40px;curso ...

  4. const let,console.log('a',a)跟console.log('a'+a)的区别

    const 创建一个只读的常量 let块级作用域 const let重复赋值都会报错 console.log('a',a) a console.log('a'+a) a2 逗号的值会有空格:用加号的值 ...

  5. JavaScript基础

    JavaScript基础 JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的处 ...

  6. 手把手教你做个人 app

    我们都知道,开发一个app很大程度依赖服务端:服务端提供接口数据,然后我们展示:另外,开发一个app,还需要美工协助切图.没了接口,没了美工,app似乎只能做成单机版或工具类app,真的是这样的吗?先 ...

  7. Android之文件数据存储

    一.文件保存数据介绍 Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的.文件可用来存放大量数据,如文本.图 ...

  8. Eclipse使用Git教程

    A:点击Window--->Show view--->other..--->Git Repositories--->[OK] B:克隆码云上的代码仓库 C:选择对应目录存储你的 ...

  9. Linux的学习笔记

    Linux,1991年,系统安全,良好的可移植性,多用户,多任务,良好的兼容性,良好的用户界面, 主流的是RedHat或者CentOS, CentOS 设置的网关 192.168.2.2 Window ...

  10. Linux监控工具介绍系列——vmstat

      说来惭愧,玩Linux这么久了,居然没有玩转vmstat这个命令,对很多指标的具体意义都有点模糊不清,花了点时间好好学习.整理一下这个命令的相关资料.因为这个命令确实比较重要,而且频繁用到. 命令 ...