Mysql数据库隔离级别 未完待续
MYSQL事务隔离级别
脏读 不可重复读 幻读 这周末搞定
四种隔离级别
InnoDB解决幻读的方案–LBCC&MVCC
InnoDB
默认的事务隔离级别是RR,它为了解决该隔离级别下的幻读的并发问题,提出了LBCC
和MVCC
两种方案。其中LBCC
解决的是当前读情况下的幻读,MVCC
解决的是普通读(快照读)的幻读。
知识点
InnoDB的RR隔离级别并没有完全解决幻读的问题。如果在同一个事务里面,只是总是执行普通的select快照读,是不会产生幻读的。
但是如果在这个事务里面通过当前读或者先更新然后快照读的形式来读取数据,就会产生幻读。
测试用表
-- auto-generated definition
create table test_read
(
id bigint auto_increment comment '主键'
primary key,
name varchar(32) default '' null comment '姓名'
)
comment '幻读测试表';
初始化数据
insert into test_read (id, name) values (1, 'wang');
insert into test_read (id, name) values (2, 'zhang');
幻读情形1
打开两个终端,连上mysql,分别启动事务1和事务2。
事务1 | 事务2 |
---|---|
start transaction; | start transaction; |
insert into test_read (name) values (‘zhao’); | – |
select * from test_read; | select * from test_read; |
查询出来的结果如下:
事务1:
1,wang
2,zhang
3,zhao
事务2:
1,wang
2,zhang
很明显事务2没有查询到事务1未提交的新插入数据。原因也很简单,因为普通的select语句是快照读,而事务b启动时,它的快照数据就已经被版本锁定了。
如果事务2进行当前读是否能够读取到事务1未提交的新插入数据呢?
我们在事务2里面执行如下命令来看看执行结果:
select * from test_read lock in share mode;
执行完成之后我们发现事务b此时会block住,原因是事务1的insert语句排它锁住了id为3的新插入数据,而事务2想请求所有行的共享锁,肯定是需要等待的。
事务1提交之后,事务2依然无法读取到事务a新插入的数据,因为事务b还是读取到的是快照数据,所以不包含事务a提交之后的新数据。
如果此时事务b使用当前读,能否获取到事务a已提交的新插入数据呢?
事务1 | 事务2 |
---|---|
start transaction; | start transaction; |
insert into test_read (name) values (‘zhao’); | – |
select * from test_read; | select * from test_read; |
commit; | – |
– | select * from test_read lock in share mode; |
查询出来的结果如下:
1,wang
2,zhang
3,zhao
可以查询到事务a已提交的新数据,所以此时使用当前读就产生了幻读。
幻读情形2
事务1 | 事务2 |
---|---|
start transaction; | start transaction; |
insert into test_read (name) values (‘zhao’); | – |
select * from test_read; | select * from test_read; |
commit; | – |
– | update test_read set name=’bbb’ where id = 3; |
– | select * from test_read; |
第一条命令使用update更新了事务a已提交的新数据,第二条命令通过普通的select语句查看快照数据。
查询出来的结果如下:
1,wang
2,zhang
3,bbb
可以看到事务a已提交的新数据被事务b使用update语句更新了,并且通过普通的select语句给查询出来了,很显然,出现了幻读。
引用