mysql 锁 事务隔离级别

主题

最近在看mysql相关的书籍.实验了一些内容.分享一下,主要是关于事务隔离级别(read-committed和repeatable-read)和锁相关的.mysql

 

不少网上文章上都能搜索到 read-committed能够防止脏数据.可是不能防止 不可重复读.sql

而repeatable-read能够防止 不可重复读.可是不能防止幻读.session

如今我想分享下具体是怎么操做的. 日志

 

不可重复读下的区别

read-committed和repeatable-read的区别究竟是什么?索引

我以为在 不可重复读 这个问题上并无涉及锁的问题.而是涉及一致性非锁定读的问题事务

 

假设有一张user,主键id int, name varchar, i varchar.it

在i这一列上有索引,非惟一.io

数据以下:table

id  name  idate

1  v1    i1

5  v5    i5

9  v9    i9

全部session的 autocommit=0 不会自动提交.

 

session A:

update user set name = 'v5-new' where id = 5;  

这个时候锁定了id=5这一列.没有commit

 

Session B:

select name from user where id = 5

查询出来是v5.这是由于RR和RC都不会读到脏数据

 

而后session A:

commited;

这个时候行最新的name已是v5-new了

 

Session B:

select name from user where id = 5

这个时候的select就有区别了.

RC读出来是v5-new, RR仍然是v5

可是要注意的是Session B在这里始终都只是通常的select,因此没有加锁.因此这里不可重复和锁我以为没有关系(可是和session A在记录上加的X锁有点关系,由于这条记录被锁定了).

那为何2种隔离级别会有区别呢? 由于一致性非锁定读的缘由

 

session B第一次读取发现记录ID=5被锁定(有X锁).那读的时候就会从undo日志里找到原始的值.也就是v5.

第二次读的时候RC和RR有区别.RC由于session A已经committed,会读最新的行数据,也就是v5-new

而RR仍然会读取以前读到的那个snap-shot版本,也就是v5.因此会有区别..

 

幻读

RR模式下加上锁能够解决幻读的问题(还原以前的数据).

实验以下:

Session A:

update user set name = 'v55' where i = 'i5';

没有committed

 

Session B:

insert into user values(6, 'v6', 'i5');

 

这个时候若是B能够committed,那就会产生幻读的问题.由于A明明修改了全部i=i5的数据.

可是却没有修改B插入的那条.

 

可是实际上Session B执行这个insert的时候回等待.

由于A锁住了i = i5的数据.因此B是插入不了的.

 

那若是B执行的是

 insert into user values(6, 'v6', 'i6'); 能够吗?

事实上也会等待.由于A会锁定i=i5的数据和它到上下两条相邻数据的区间.

也就是说 i1-i5, i5, i5-i9的数据都被锁住了.都是不能插入的.

 insert into user values(10, 'v10', 'ia');

这条记录就能够插入.由于ia在i9以后(字母大于数字).

 

mysql对主键会锁单条记录.可是对非惟一的通常的索引,会锁单条记录加上上下范围 

相关文章
相关标签/搜索