我们都知道数据库的事务具有ACID的四个属性:原子性,一致性,隔离性和持久性。然后在多线程操作的情况下,如果不能保证事务的隔离性,就会造成数据的修改丢失(事务2覆盖了事务1的修改结果)、读到脏数据(事务2读到了事务1未回滚的数据)、不可重读(事务2读到了事务1未提交的修改)和幻读(事务2读到了事务1未提交的增删)等。保证事务隔离性可以防止事务出现以上问题,那么数据库又是怎么来保证事务的隔离性的呢?

  mysql使用两阶段协议来保证事务执行的串行化从而保证事务的隔离性的。
  首先,为了保证数据访问的串行,每个数据资源都有对应的锁(mysql的锁只细化到行级),那么只要保证每个数据资源的访问都是串行化的,然后整个数据库不就可以保证每个数据操作之间的隔离性了么,就是说:

  只要每个数据操作都有对应的锁覆盖,然后把每个操作都加上对应的锁,这样可以保证事务执行的串行化么?

  答案是:可以保证,但是有个前提是每个事务只包含对一个数据的操作。事实上mysql也默认是这样做的:如果用户没有手动开启事务,那么根据AUTOCOMMIT机制,mysql默认将每一个数据库操作封装成一个事务来处理。

  然而实际情况中,很多时候一个事务不只包含一个数据库操作,比如电商平台在生成订单时,一个事务里包含了对订单表、用户表、商品表等的操作。在多线程操作的情况下,如果只用数据库的锁来保证的话,就会出现上面所提到的一些数据异常情况。这时候就需要两阶段协议来保证事务的隔离性了。那么进入今天的主题:

  两阶段协议如何保证多事务操作之间的隔离性?

  上面说过,只要事务执行是串行的,事务之间就是隔离的,在网上搜索两阶段协议为何能保证串行化,只搜到一个封锁定理:如果事务是良构的且是两阶段的,那么任何一个合法的调度都是可串行化的。 既然是定理,那一定是严格成立且可证明的,于是顺藤摸瓜,找到了封锁定理的证明(<事务处理:概念与技术>>这本书的7.5.8.2节)。

  首先我们解析命题:

  条件:良构的事务、两阶段、合法的调度

  结论:是可串行化的。

  在书上找到条件的描述:

  如果事务的每个READ、WRITE、 UNLOCK都被响应的锁覆盖,且所有的锁都是在事务结束时释放,那么称这样的事物是良构的。(mysql的表和行数据在被操作时,都有对应的锁覆盖) 

  如果一个事务可以分成两个阶段,只请求封锁的扩展阶段和只释放锁的收缩阶段,那么称之为两阶段的事务。(mysql采用两阶段封锁协议)

  调度是一组事务的操作的某种合并结果。(mysql支持多事务并行执行)

  一个调度是合法的,如果同一时间没发生两个不同事务的锁冲突。(mysql需要保证并行事务不冲突)

  因为每个事务T都是良构的,所以必定对应着一个解锁操作Unlock,事务T的解锁操作步骤在调度中的索引为St。

  假设在调度中事务T1在事务T2之前执行,T1<<<T2,则事务T2依赖事务T1,使得事务T1对对象O的操作步骤a1在事务T2对对象O的操作步骤a2之前,那么a1和a2必定有一个步骤对象O正覆盖着排他锁(WRITE)(因为如果是两个挨着的读事务(READ)不存在依赖关系,所以他们的执行顺序没有明确的等价执行序列),如果是a1时对象O覆盖着一个XLOCK(排他锁),a2时对象O应该覆盖着一个SLOCK(共享锁)或XLOCK(排他锁),与前面的XLOCK互斥,又由于是两阶段的,所以在a1和a2之间,会存在一个事务T1给对象O解锁的Unlock操作步骤St1,事务T2的解锁操作步骤St2在a2之后,所以有:St1<<<St2,即事务T1的解锁在事务T2的解锁之前。同理在a2是WRITE操作的时候也成立。如果调度是不可串行化的,那么必然存在T1<<<T2时,St2<<<St1,与上述结论矛盾,所以:

  如果一个调度包含的事物都是良构的且为两阶段的,那么该调度是可串行化的。

  可能有人会问,为什么不给每个事务加排他锁来保证多事务执行的串行化呢?

  是因为如果把读锁也定义为排他锁的话,会大大的降低并发读的效率,而查询操作在数据库的操作中占了很大的比例,所以mysql默认采用的可重复读的隔离级别,用两阶段协议和全场景覆盖的锁来保证执行结果的串行化,并没有采用全用排他锁来保证串行化。

  

  

  

mysql的两阶段协议(封锁定理,虫洞事务)的更多相关文章

  1. 使用golang理解mysql的两阶段提交

    使用golang理解mysql的两阶段提交 文章源于一个问题:如果我们现在有两个mysql实例,在我们要尽量简单地完成分布式事务,怎么处理? 场景重现 比如我们现在有两个数据库,mysql3306和m ...

  2. MySQL binlog 组提交与 XA(两阶段提交)

    1. XA-2PC (two phase commit, 两阶段提交 ) XA是由X/Open组织提出的分布式事务的规范(X代表transaction; A代表accordant?).XA规范主要定义 ...

  3. MySQL binlog 组提交与 XA(分布式事务、两阶段提交)【转】

    概念: XA(分布式事务)规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口.XA为了实现分布 ...

  4. MySQL binlog 组提交与 XA(两阶段提交)--1

    参考了网上几篇比较靠谱的文章 http://www.linuxidc.com/Linux/2015-11/124942.htm http://blog.csdn.net/woqutechteam/ar ...

  5. 聊一聊 MySQL 中的数据编辑过程中涉及的两阶段提交

    MySQL 数据库中的两阶段提交,不知道您知道不?这篇文章就简单的聊一聊 MySQL 数据库中的两阶段提交,两阶段提交发生在数据变更期间(更新.删除.新增等),两阶段提交过程中涉及到了 MySQL 数 ...

  6. 全网最牛X的!!! MySQL两阶段提交串讲

    目录 一.吹个牛 二.事务及它的特性 三.简单看下两阶段提交的流程 四.两阶段写日志用意? 五.加餐:sync_binlog = 1 问题 六.如何判断binlog和redolog是否达成了一致 七. ...

  7. flink-----实时项目---day07-----1.Flink的checkpoint原理分析 2. 自定义两阶段提交sink(MySQL) 3 将数据写入Hbase(使用幂等性结合at least Once实现精确一次性语义) 4 ProtoBuf

    1.Flink中exactly once实现原理分析 生产者从kafka拉取数据以及消费者往kafka写数据都需要保证exactly once.目前flink中支持exactly once的sourc ...

  8. MySQL两阶段提交

    参数介绍 innodb_flush_log_at_trx_commit 0: 每隔1s,系统后台线程刷log buffer,也就是把redo日志刷盘,这里会调用fsync,所以可能丢失最后1s的事务. ...

  9. 关于分布式事务、两阶段提交、一阶段提交、Best Efforts 1PC模式和事务补偿机制的研究 转载

    1.XA XA是由X/Open组织提出的分布式事务的规范.XA规范主要定义了(全局)事务管理器(Transaction Manager)和(局部)资源管理器(Resource Manager)之间的接 ...

随机推荐

  1. IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

    1.引言 基本上以陌生人社交为主的IM产品里,都会增加“附近的人”.“附近的xxx”这种以LBS(地理位置)为导向的产品特色(微信这个熟人社交产品里为啥也有“附近的人”?这当然是历史原因了,微信当初还 ...

  2. PTA刷题记录(3)

    团队天梯赛-------(3)分值:15 给定一个 k 位整数 N=d​k−1​​10​k−1​​+⋯+d​1​​10​1​​+d​0​​ (0≤d​i​​≤9, i=0,⋯,k−1, d​k−1​​ ...

  3. Pycharm创建项目时 自动添加头部信息

    1.打开PyCharm,选择File--Settings 2.依次选择Editor---Code Style-- File and Code Templates---Python Script 3.. ...

  4. python入门递归之阶乘

    def recurursion(n): if n == 1: return 1 else: return n * recurursion(n-1) number = int(input("请 ...

  5. vue学习笔记(五)条件渲染和列表渲染

    前言 在众多的编程语言中,我们的基础语法总是少不了一些专业语法,比如像定义变量,条件语句,for循环,数组,函数等等,vue.js这个优秀的前端框架中也有同样的语法,我们换一个名词,将条件语句改成专业 ...

  6. windows,linux安装redis

    windows安装redis   Redis介绍 Redis是什么 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string.list ...

  7. java编程思想第四版第十一章总结

    1. 容器类被分为两类:Collection和Map Collection是一个接口:包括: List接口: ArrayList:按照被插入顺序保存元素, 查询快, 增删改慢 LinkedList:按 ...

  8. 领扣(LeetCode)最大连续1的个数 个人题解

    给定一个二进制数组, 计算其中最大连续1的个数. 示例 1: 输入: [1,1,0,1,1,1] 输出: 3 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3. 注意: 输入的数组 ...

  9. SecureCRT 多个会话显示在同一窗口

  10. 原创|我是如何从零学习开发一款跨平台桌面软件的(Markdown编辑器)

    原始冲动 最近一直在学习 Electron 开发桌面应用程序,目的是想做一个桌面编辑器,虽然一直在使用Typore这款神器,但无奈Typore太过国际化,在国内水土不服,无法满足我的一些需求. 比如实 ...