zoukankan      html  css  js  c++  java
  • MySql事务隔离的特点与实现

    事务隔离的级别

    MySql的事务隔离级别一共有四种情况。分别是:读未提交、读已提交、可重复读、串行化

    • 读未提交:指的是一个事务可以读取到另一个未提交事务所做出的修改。
    • 读已提交:指一个事务执行过程中可以读取另一个事务已提交的修改。
    • 可重复读:指一个事务在启动的瞬间,事务所看到的数据保持不变。即使其它事务对数据有提交修改,对于可重复读隔离级别的事务也是不可见的。
    • 串行化:指事务所读写的数据都需要通过悲观锁控制。采用读写锁的实现,当两个事务出现写冲突时,未获取锁的事务必须等待。

    基于mvcc的事务隔离

    mvcc全称为多版本并发控制(Multiversion concurrency control),应用于读提交和可重复读这两个隔离级别。所以下面讲解mvcc的实现就基于数据库是使用Innodb引擎的可重复读级别。
    这个词语可以拆分为两个关键字,一个是多版本、一个是并发控制。那么通过引出两个问题,就可以初步的了解mvcc的控制下,用户事务能看到什么数据,怎么更新数据。

    • 如何保存多个版本?
    • 并发查询修改的时候,事务能看到哪个版本?

    如何保存多个版本

    首先,mysql中保存的数据,是只有一份的。但是通过undolog(回滚日志)的记录,能从当前数据计算出历史版本的数据。
    那什么是undolog呢?undolog就是当某一行的数据发生变更时,数据库总会记录一份与当前操作的反向逻辑操作。如当前事务的操作把age=18+1,那么在事务提交的时候,就会在undolog记录这一行的回滚日志,大致是把age从19变为18。每个版本的记录都能被引擎轻易的找到。
    但是仔细想想,undolog只记录了操作,那根据隔离级别的定义,哪个版本是当前事务可以读取的呢?所以undolog里面还记录了修改这条记录的事务id,而名称为:row trx_id。同时,事务id是严格递增的,不会出现重复。

    并发查询修改的时候,事务能看到哪个版本

    要解答这个问题,我们先来重复一遍可重复读得定义:一个事务在启动的瞬间,即使其它事务对数据有提交修改,事务所看到的数据保持不变。
    这里的效果仿佛就是数据库引擎给我们创建的一个视图,后续的查询都在这个视图上进行,不受其它事务的影响。但是实际上,如果每个事务都创建一个视图,一个表上有几百m的数据,那事务一多起来数据库是必定崩溃的。
    所以,这个的视图是逻辑上的视图,利用上面提到的undolog做多版本控制。在开启一个事务的时候,当前事务需要记录一次所有未提交的事务,并将它们用数组存储起来,同时确定最大值=max(事务id)+1与最小值=min(事务id)。
    最小值的含义:小于这个值的事务是已经提交的。
    最大值的含义:大于这个值的事务对于当前事务都是未开始的。
    然后,当前事务查询一条数据时,当前的事务id会与这条记录的row trx_id作比较,如果这个row trx_id大于最小值怎么办?还记得之前的undolog吗,那就利用undolog做计算,计算出上一个版本的值,再与上个版本的row trx_id做比较,如果小于最小值,那就是可以看见的版本。
    这样,每个事务都可以利用自己的事务id确定自己可以看见的数据,这就是逻辑上的视图。

    事务隔离下的更新逻辑

    从一个例子演示,可重复读事务隔离级别下是如何更新的。
    有一个表:

    id k
    1 1

    下图中,有一个数据,最新的记录是由事务90提交的。按照时间线有如下操作:
    1.然后事务B先开启,收集了当前未提交的事务id,形成逻辑视图。
    2.事务C后开启,随后对k进行+1操作,当前版本k变为2,事务C提交
    3.事务B对k进行+1操作。
    4.查询k的值。
    更新流程

    问题:当前k的值是多少?
    如果按照可重复读的隔离级别定义,这里事务B读到的k值应该为1才对。但是,这个理解是错误的,事务b查询到的k值应该为3。

    • 为什么会这样?
      那就要引入当前读这个概念:可重复读隔离级别下,事务开启后的数据读到的值不变,但是事务更改数据的时候,是读取最新版本的数据用作更新的。所以,当事务B执行k+1操作的时候,会读取最新版本k=2然后再+1。

    • 为什么需要当前读?
      我认为,如果事务B在更新的时候不读取最新版本的值,而是使用自身建立的视图,那么就会把已提交的事务C所做出的修改给覆盖,这样也就违反了事务的持久性原则。

    • 如果两个事务同时写怎么办?
      当两个事务都对同一行进行修改时,那就需要用到写锁。先获取锁的事务可以进行修改,直到事务提交,另一个事务才能进行修改。

    知识来源参考:https://time.geekbang.org/column/article/70562

  • 相关阅读:
    SQL 在数据库中查找包含指定关键字的存储过程或函数
    根据名称查找存储过程或函数
    根据最后修改时间查找存储过程或函数
    SQL 数据过度事务模板
    Feeling something wrong
    发布一个倒计时软件(C# 开源)
    SpringBoot中的配置文件信息加密
    springboot中mysql连接配置
    React学习2_运行项目
    React学习0_文章目录
  • 原文地址:https://www.cnblogs.com/hill1126/p/mysql_mvcc.html
Copyright © 2011-2022 走看看