最近在看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对主键会锁单条记录.可是对非惟一的通常的索引,会锁单条记录加上上下范围