1.四种隔离级别下数据不一致的情况

 
脏读
不可重复读
幻读
RU
RC(快照读)
RC(当前读)
RR(快照读)
RR(当前读)
Serializable(串行化)
## 关于RR快照读时会不会造成幻读,我举一个例子,RR隔离级别,id主键
## 我也不知道这算不算幻读,
事务A 事务B
begin; begin;

select count(*) from test;

结果:1

 
  insert into test values(4,'asd')

update test set name='zxcs';

 
阻塞  
  commit

select count(*) from test;

结果:2

 

那什么是当前读,什么是快照读呢?

当前读:select * from table where ? lock in share mode;
    select * from table where ? for update;
    insert into table values (…);
    update table set ? where ?;
    delete from table where ?;
快照读: select * from table where ?
 
简单来说,当前读就是带S锁读或者带X锁读,或者dml操作,快照读:读不加锁,读写不冲突。
 
快照读要从MVCC说起
 
MVCC增加了一种可以不带锁的读取数据方式,但是读取的时版本快照,并不是最新内容
快照读读取的就是MVCC中的版本快照
MVCC只支持Mysql的InnoDB引擎中的已提交读(READ COMMITTD)和可重复读(REPEATABLE READ)这两种隔离级别下使用

MVCC的实现原理:----UNDO LOG + 隐藏字段trx_id 和roll_pointer

## trx_id : 对该记录最新修改的事务id

## roll_pointer:老版本号  --保存在undo log中

## 如果一个表有两个字段id和name ,实际上是这样的,会有两个是隐藏字段,其实应该是3个隐藏字段,还有一个跟MVCC无关。

id
name
trx_id
roll_pointer
1 lxl 40 上一个版本记录的地址

举个栗子,update table set name= 'lxlxlxl' where id=1;(id是主键),假如当先这条dml的事务号为41

id name trx_id roll_pointer
1 lxl 40 上一个版本记录的地址

### 这条记录会被放到undo log 中

### 然后

id

name trx_id roll_pointer
1 lxlxlxl 41 trx_id=40的地址

###这条记录会放到表中

那快照读的时候是怎么判断版本号的呢?

ReadView中主要就是有个列表来存储我们系统中当前活跃着的读写事务,也就是begin了还未提交的事务。通过这个列表来判断记录的某个版本是否对当前事务可见。假设当前列表里的事务id为[80,100]。

如果你要访问的记录版本的事务id为50,比当前列表最小的id80小,那说明这个事务在之前就提交了,所以对当前活动的事务来说是可访问的。

如果你要访问的记录版本的事务id为85,发现此事务在列表id最大值和最小值之间,那就再判断一下是否在列表内,如果在那就说明此事务还未提交,所以版本不能被访问。

如果不在那说明事务已经提交,所以版本可以被访问。如果你要访问的记录版本的事务id为110,那比事务列表最大id100都大,那说明这个版本是在ReadView生成之后才发生的,所以不能被访问。
 
这些记录都是去版本链里面找的,先找最近记录,如果最近这一条记录事务id不符合条件,不可见的话,再去找上一个版本再比较当前事务的id和这个版本事务id看能不能访问,以此类推直到返回可见的版本或者结束。
 
版本链就是每条记录的隐藏字段roll_pointer组成的链表

那么我有一个问题,当一个事务执行一个dml,是在commit后对表,还是在执行完dml后对表进行修改?

我们可以来对比下RU 和 RC 隔离级别

RU 是为什么会造成脏读的现象?就是为什么会读到未提交的数据?

RC 为什么不会造成脏读?

我们假设执行完dml 就会对表进行修改,而不是commit之后修改

RU :id是主键

事务A 事务B
begin; begin
  update table set name= 'lxlxlxl' where id=1;
select * from table  
能读到事务B修改的数据  

在RC,RR,RS中事务B需要commit 才能被其他事务看到

可以说明

执行完dml 就会对表进行修改,而不是commit之后修改

再来看RC:id是主键

事务A 事务B
begin;  begin;  
  update table set name= 'lxlxlxl' where id=1;
select * from table where id=1 lock in share mode  

此时事务A阻塞,S锁和 事务B的X锁冲突

此时事务B对表格已经修改,也成立

但是因为锁冲突的原理不会被其他当前读的事务所看到

如果这里采用快照读不会阻塞,也不会读到更改,因为只会读到上一个版本的记录

 
  commit;
执行,并看到事务B的修改  
 
 
 
 
 
 
 
 
 
 
 
###我的意思是其他在执行完DML后就会对表格进行修改,也即会更改行记录的trx_id,但是在commit之后才会被发现,因为在commit之前,执行dml之后该记录带X锁,会与其他想这条记录的事务冲突,所以在这个期间不会被其他事务看到修改。
 
2. 关于2pl

2-PL  :Two-phase Locking ,锁操作分为两个阶段,加锁阶段和解锁阶段,并且保证加锁阶段与解锁阶段不相交,

2PL就是将加锁/解锁分为两个完全不相交的阶段。加锁阶段:只加锁,不放锁。解锁阶段:只放锁,不加锁。

关于2-pl 有以下变种:

C2PL  : 在事物开始时对所有需要访问的数据获取锁。不存在死锁问题,要么事务等待不能开始,要么就已经得到了全部所需的锁

S2PL  : 严格2PL,事务持有的写锁必须提交后再释放,读锁在阶段二时释放

SS2PL:  强严格2PL,事务持有的所有锁必须在事务提交(完成)后释放;

3. 分析一下 一个简单的update在不同隔离级别下的效果

update test set name='lxl' where id=5

  id为主键 id为二级唯一索引 id为二级普通索引 id不是索引
RU

在主键上id=5的记录加上X锁

操作完成后释放所有X锁

先在二级唯一索引上进行带锁的当前读(for update),

找到id=5的记录后加上X锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁,

操作完成后释放所有X锁

现在二级普通索引上进行待锁的当前读(for update),

找到所有id=5的记录后加上X锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁,

操作完成后释放所有X锁,

跟唯一索引的区别是:唯一索引只有一条记录

使用半一致性读

SQL走聚簇索引的全扫描进行过滤把每条记录都加上X锁,

对于不满足where id=5的记录释放掉锁,

最终只有符合条件的记录带上X锁,

RC

在主键上id=5的记录加上X锁

操作完成后释放所有X锁

先在二级唯一索引上进行带锁的当前读(for update),

找到id=5的记录后加上X锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁,

操作完成后释放所有X锁

现在二级普通索引上进行待锁的当前读(for update),

找到所有id=5的记录后加上X锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁,

操作完成后释放所有X锁,

(有人会说半一致性读,确实,半一致性读,能肯定的是,没执行update之前没有放锁,可以测试,但不能肯定他不合条件的是在获取所有锁->释放不合条件记录的X锁 -> 执行

还是获取所有锁-> 执行->释放不合条件记录的X锁 ,下面拿例子说一下这个不一致性读)

跟唯一索引的区别是:唯一索引只有一条记录

使用半一致性读

SQL走聚簇索引的全扫描进行过滤把每条记录都加上X锁,

对于不满足where id=5的记录释放掉锁,

最终只有符合条件的记录带上X锁,

RR

在主键上id=5的记录加上X锁

操作完成后释放所有X锁

先在二级唯一索引上进行带锁的当前读(for update),

找到id=5的记录后加上X锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁,

操作完成后释放所有X锁

例如 id 的二级索引上有值【1,2,5,7】

现在二级普通索引上进行待锁的当前读(for update),

找到所有id=5的记录后加上X锁,以及把【2-5】【5-5】【5-7】之间加上间隙锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁

操作完成后释放所有X锁和gap锁,跟唯一索引的区别是唯一索引只有一条记录

 在聚集索引上扫表,

并对每条记录加上X锁,

但不会像RC那样把不符合条件的释放掉,

直到事务结束,

同时对每个间隙加上gap锁,

例如有主键[1,2,3,4],

在1-2  , 2-3,  3-4,4-~,所有间隙加上gap锁

操作结束,把所有X锁和gap锁释放掉

RS

在主键上id=5的记录加上X锁

操作完成后释放所有X锁

先在二级唯一索引上进行带锁的当前读(for update),

找到id=5的记录后加上X锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁,

操作完成后释放所有X锁

例如 id 的二级索引上有值【1,2,5,7】

现在二级普通索引上进行待锁的当前读(for update),

找到所有id=5的记录后加上X锁,以及把【2-5】【5-5】【5-7】之间加上间隙锁,

然后通过主键值回到主键索引(聚集索引)中把对应的记录加上X锁

操作完成后释放所有X锁和gap锁,跟唯一索引的区别是唯一索引只有一条记录

在聚集索引上扫表,

并对每条记录加上X锁,

但不会像RC那样把不符合条件的释放掉,

直到事务结束,

同时对每个间隙加上gap锁,

例如有主键[1,2,3,4],

在1-2  , 2-3,  3-4,4-~,所有间隙加上gap锁

操作结束,把所有X锁和gap锁释放掉

结论:update test set name='lxl' where id=5

 

           (1)在id为主键的情况下,在RU,RC,RR,S隔离级别下加锁和释放锁的过程都是一样的

 

           (2)在id为二级唯一索引时,在RU,RC,RR,S隔离级别下加锁和释放锁的过程也是一样的

 

           (3)在id为二级普通索引时,在RU,RC下过程一样,在RR,S隔离级别下多了gap锁防止幻读

 

           (4)在id不是索引的时,RU隔离级别下:;

 

                                                    RC隔离级别下,SQL走聚簇索引的全扫描进行过滤把每条记录都加上X锁,对于不满足where id=5的记录释放掉锁,

 

                                                    RR隔离级别下,SQL走聚簇索引的全扫描对每条记录加上X锁,但不会像RC那样把不符合条件的释放掉,直到事务结束,符合2PL原则。同时                                                      对每个间隙加上gap锁

 

                                                    S隔离级别下,与RR级别一样,只不过强制把事务进行排序,不允许并发操作

4.分析select ,update,delete 在RC级别下不命中索引的操作

RC隔离级别,age不是索引
select * from test where age=5;

## 分析:最后只有主键上age=5的记录带S锁

## 因为 S2PL的原因,读操作在读完可以把部分读锁释放不必等到commit再释放,而写锁必须事务提交才能释放

update viptest.test set name='lxl' where age=5;

## 分析:最后只有主键上age=5的记录带X锁

## 因为半一致性读的原因,当读到有锁冲突的记录的时候,mysql会判断,如果不是update需要的数据,如果不是则跳过该记录。

## 如果读到没加锁的记录话,加锁和释放锁的操作不会被省略

delete from viptest.test where age=5;

## 分析,假如主键上有age 【1,10】范围的数据,因为没走索引,【1,10】每个条记录加上X锁。

## 半一致性读只对update有效

 

MYSQL隔离级别 与 锁的更多相关文章

  1. mysql 隔离级别与锁

    1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约 ...

  2. Mysql隔离级别,锁与MVCC

    关键词:事务,ACID,隔离级别,MVCC,共享锁,排它锁 阅读本文前请先阅读http://hedengcheng.com/?p=771 http://www.hollischuang.com/arc ...

  3. mysql隔离级别与锁,接口并发响应速度的关系(2)

    innoDB默认隔离级别 mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-------------- ...

  4. mysql隔离级别与锁,接口并发响应速度的关系(1)

    默认隔离级别:可重复读 原始数据 | id | name | addr | | nick | NULL | 事务1 事务2 start transaction start transaction ; ...

  5. MySQL数据库引擎、事务隔离级别、锁

    MySQL数据库引擎.事务隔离级别.锁 数据库引擎InnoDB和MyISAM有什么区别 大体区别为: MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调的是性能 ...

  6. 重新学习MySQL数据库9:Innodb中的事务隔离级别和锁的关系

    重新学习MySQL数据库9:Innodb中的事务隔离级别和锁的关系 Innodb中的事务隔离级别和锁的关系 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁 ...

  7. MySQL事务隔离级别,锁(转)

    add by zhj: 本文针对的是MySQL的InnoDB存储引擎,不适用于MySQL的其它存储引擎和其它数据库 原文:MySQL数据库事务隔离级别(Transaction Isolation Le ...

  8. Mysql数据库事务的隔离级别和锁的实现原理分析

    Mysql数据库事务的隔离级别和锁的实现原理分析 找到大神了:http://blog.csdn.net/tangkund3218/article/details/51753243 InnoDB使用MV ...

  9. MySql各事务隔离级别及锁问题

    聊事务隔离级别和锁问题之前首先得理解事务的隔离级别和共享锁及独占锁的概念: 事务的隔离级别:   脏读 不可重复读 幻读 Read uncommitted √ √ √ Read committed × ...

随机推荐

  1. 我是如何从通信转到Java软件开发工程师的?

    我的读者里面有绝大部分都是在校学生,有本科的,也有专科的,我在微信里收到很多读者的提问,大部分问题都跟如何学习编程有关,有换专业自学的.有迷茫不知道如何学习的.有报培训班没啥效果的等等,我能感受到他们 ...

  2. 人生苦短,学用python

    1. 我为什么开始学着用 python 啦?   扯扯网上疯传的一组图片.网上流传<人工智能实验教材>的图片,为幼儿园的小朋友们量身打造的实验教材,可谓是火了.甚至有网友调侃道:pytho ...

  3. 多线程学习笔记(四)---- Thread类的其他方法介绍

    一.wait和 sleep的区别 wait可以指定时间也可以不指定时间,而sleep必须指定时间: 在同步中时,对cpu的执行权和锁的处理不同: wait:释放执行权,释放锁:释放锁是为了别人noti ...

  4. 使用vant的时候,报错:component has been registered but not used以及vant的使用方法总结

    使用vant的时候,报错:component has been registered but not used以及vant的使用方法总结 在使用vant的时候. 想按需引入,于是安装了babel-pl ...

  5. 《Three.js 入门指南》3.0 - 代码构建的最基本结构。

    3.0 代码构建的最基本结构 说明: 我们必需首先知道,Three.js 的一些入门级概念: 我们需要知道,OpenGL 是一套三维实现的标准,为什么说是标准,因为它是跨平台,跨语言的.甚至CAD以及 ...

  6. PTA数据结构与算法题目集(中文) 7-39魔法优惠券 (25 分)

    PTA数据结构与算法题目集(中文)  7-39魔法优惠券 (25 分) 7-39 魔法优惠券 (25 分)   在火星上有个魔法商店,提供魔法优惠券.每个优惠劵上印有一个整数面值K,表示若你在购买某商 ...

  7. egg.js部署到服务器

    关于egg.js项目部署服务器的问题 我使用的是腾讯云centos , 部署前需要确保服务器上安装了mysql, node . mysql下载:https://dev.mysql.com/downlo ...

  8. Wirte-up:攻防世界Web解题过程新手区01-06

    文章更新于:2020-02-18 说明:为了标识图片边界,有些图片加了红线以增强观感. 注1: web 环境搭建参见: Windows&linux使用集成环境搭建 web 服务器 注2:DVW ...

  9. django自定义404和500页面

    from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.s ...

  10. 阿里云服务器扩展分区和文件系统_Linux数据盘

    官方文档永远是最好的 https://help.aliyun.com/document_detail/25452.html?spm=a2c4g.11186623.6.786.5fde4656Ln6AO ...