深度剖析 MySQL 事务隔离!

概述

今天主要分享下MySQL事务隔离级别的实现原理,因为只有InnoDB支持事务,所以这里的事务隔离级别是指InnoDB下的事务隔离级别。

隔离级别

1、读未提交:一个事务可以读取到另一个事务未提交的修改。这会带来脏读,幻读,不可重复读问题

2、读已提交:一个事务只能读取另一个事务已经提交的修改。其避免了脏读,仍然存在不可以重复读和幻读问题

3、可重复读:同一个事务中多次读取相同的数据返回的结果是一样的。其避免了脏读和不可重复读问题,但是幻读依然存在

4、串行化:事务串行之行。避免了以上所有问题
在这里插入图片描述
以上是SQL-92标准中定义的四种隔离级别。在MySQL中,默认的隔离级别是REPEATABLE-READ(可重复读),并且解决了幻读问题。

注:不可重复读重点在于Update和delete,而幻读的重点在于insert。

MVCC

MVCC的全称是多版本并发控制。MVCC使得InnoDB的事务隔离级别下执行一致性读操作有了保证。

简单说就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。这是一个用来增强并发性的强大技术,可以使得查询不用等待另一个事务释放锁。

如下图所示:
在这里插入图片描述
MVCC会给每一行增加三个字段,分别是:DB-TRX-ID、DB-ROLL-PTR、DB-ROW-ID

增删查改

在InnoDB中,给每行增加两个隐藏字段来实现MVCC,一个用来记录数据行的创建时间,另一个用来记录行的过期时间。

在实际操作中,存储的并不是时间,而是事务版本号,每开启一个新事务,事务的版本号就会递增。所以增删改查中对版本号的作用如下:

select:
读取创建版本小于或等于当前事务版本号,并且删除版本为空或大于当前事务版本的记录。这样可以保证在读取之前记录都是存在的

insert:
将当前事务的版本号保存至行的创建版本号

update
新插入一行,并以当前事务版本号作为新行的创建版本号,同时将原记录行的删除版本号设置为当前事务版本号

delete
将当前事务版本号保存至行的删除版本号

快照读和当前读

快照读:读取的是快照版本,也就是历史版本

当前读:读取的是最新版版

普通的 select 就是快照读,而 update,delete,insert,select…LOCK In SHARE MODE,SELECT…for update 就是当前读

一致性非锁定读和锁定读

首先看看下面的图:
在这里插入图片描述
1、锁定读

在一个事务中,标准的SELECT语句是不会加锁,但是有两种情况例外。

SELECT … LOCK IN SHARE MODE

SELECT … FOR UPDATE

SELECT … LOCK IN SHARE MODE:给记录假设共享锁,这样其他事务职能读不能修改,直到当前事务提交

SELECT … FOR UPDATE:给索引记录加锁,这种情况跟UPDATE的加锁情况是一样的

2、一致性非锁定读

consistent read(一致性读),InnoDB用多版本来提供查询数据库在某个时间点的快照。

如果隔离级别是REPEATABLE READ,那么在同一个事务中的所有一致性读都读的是事务中第一个的读读到的快照;如果是READ COMMITTED,那么一个事务中的每一个一致性读都会读到它自己刷新的快照版本。

consistent read(一致性读)是READ COMMITTED和REPEATABLE READ隔离级别下普通SELECT语句默认的模式。一致性读不会给它锁访问的表加任何形式的锁,因此其他事务可以同时并发的修改它们。

Record Locks(记录锁):在索引记录上加锁

Gap Locks(间隙锁):在索引记录之间加锁,或者在第一个索引记录之前加锁,或者在最后一个索引记录之后加锁

Next-Key Locks:在索引记录上加锁,并且在索引记录之前的间隙加锁。相当于Record Locks与Gap Locks的一个结合

假如一个索引包含以下几个值:10,11,13,20.那么这个索引的next-key锁将会覆盖以下区间:

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

总结

在默认的隔离级别中,普通的SELECT用的是一致性读不加锁。而对于锁定读,UPDATE和DELETE,则需要加锁,至于加什么锁是有不同情况的。

如果对一个唯一索引使用了唯一的检索条件,那么只需要锁定相应的索引记录就好;如果是没有使用唯一索引作为检索条件,或者用到了索引范围扫描,那么将会使用间隙锁或者next-key锁来以此阻塞其他会话向这个范围内的间隙插入数据

利用MVCC实现一致性非锁定读,保证在同一个事务中多次读取相同的数据返回的结果是一样的,解决了不可重复读问题.

利用Gap Locks和Next-key可以阻止其他事务在锁定区间内插入数据,解决了幻读问题.

总之,MySQL的默认隔离级别的实现依赖于MVCC和锁,准确点说就是一致性读和锁。

因为转账的交易场景 联想到要加transaction事物 但是事物是什么?
4个特性:原子性,一致性,隔离性,持久性
由于并发较大,session较多,事物存在几个问题:
1、sessionA select sessionB update
但没有commit session select 两次查询的数据不一样
脏读
2、sessionA select sessionB update成功了 sessionA select 两次读取的数据不一样,导致不可重复读
不可重复读
3、sessionA select sessionB insert 成功了 sessionA select 读了两条数据
幻读 数据库为了解决这三个问题,
sql92提出了事物的隔离级别 1、未提交读:啥也不解决 2、已提交读:不读未提交的事物数据,解决了脏读 3、可重复读:解决不了幻读 4、串行操作:缺点是效率太低,容易产生阻塞

上述隔离级别的实现方式是 1、snapshot 2、加上lock

lock又分行级锁和表级锁 以innoDb为例:行级锁,又分共享锁和排他锁 表级锁:意向共享锁和意向排它锁,为了解决效率问题

锁的原理:是锁的索引

锁算法: 1、临键锁(next-key lock) innoDB:默认采用的是next-key
lock算法,因为innoDB的设计默认是id为自增主键 2、间隙锁(gap lock)
属于写锁:锁的是间隙中的insert、update操作,不锁select,这样innoDB就解决了幻读的问题 3、(记录锁)record

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值