MySQL隔离级别

一、隔离级别导致的问题

  1. 脏读:A事物允许读取到B事物未提交的数据。
  2. 不可重复读:A事物在时间点T1读取了一些记录,在T2时再想重新读取一次同样的这些记录时,这些记录可能已经被改变、或者消失不见。
  3. 幻读:A事物在任意时刻查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。

二、事物隔离级别

  1. Read Uncommitted
  2. Read Committed
  3. Repeatable Read
  4. Serializable

每种隔离级别产生的问题:

隔离级别 脏读 不可重复读 幻读
Read Uncommitted Y Y
Read Committed N Y Y
Repeatable Read(MySQL默认事物隔离级别)  N Y 
Serializable
N N N

三、测试

1.首先检查一下MySQL的版本号

select version();

MySQL隔离级别_第1张图片


2.查看一下系统的隔离级别和回话隔离级别

select @@global.tx_isolation, @@tx_isolation;

MySQL隔离级别_第2张图片


3.修改当前会话隔离级别,方便做测试

set session tx_isolation='read-uncommitted';

select @@global.tx_isolation, @@tx_isolation;

MySQL隔离级别_第3张图片

可以发现测试会话的隔离级别变成了不可重复读


4.修改系统级别的隔离级别

set global tx_isolation='read-uncommitted';

select @@global.tx_isolation, @@tx_isolation;

MySQL隔离级别_第4张图片

此时系统级和会话级别的事物隔离级别都变成了:READ-UNCOMMITTED


5.关闭SQL自动提交功能

set autocommit=off;

show variables like 'autocommit';

MySQL隔离级别_第5张图片


6.建立测试表

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8


7.测试脏读

Transaction A Transaction B
start transaction;  
MySQL隔离级别_第6张图片

start transaction;


insert into user(name, age) values ('张三',20);

MySQL隔离级别_第7张图片

此时Transaction B尚未提交,但是Transaction A已经读取到B更新的数据了

 
  rollback;

MySQL隔离级别_第8张图片


此时Transaction B回滚了,但是Transaction A已经读取不到刚刚那条记录了

 
   
按照上图的执行顺序,脏读就这样产生了。


8.测试不可重复读

set global tx_isolation='read-committed';
set session tx_isolation='read-committed';

Transaction A Transaction B
start transaction;  
MySQL隔离级别_第9张图片  
  start transaction;


insert into user(name, age) values ('李四',30);

MySQL隔离级别_第10张图片

TransactionB未提交,所以TransactionA读取不到B的修改

 
  commit;

MySQL隔离级别_第11张图片

TransactionB提交,所以TransactionA读取到B的修改

 
按照上图的执行顺序,Transaction A在同一个事物中,不同时间点上,读取到的数据是不一样的,这就叫不可重复读。


9.测试可重复读

set global tx_isolation='repeatable-read';
set session tx_isolation='repeatable-read';

修改隔离级别为可重复读,这样同一个事物Transaction A中任一时刻读取的数据是可以保持一致了,但是紧接着就带来了幻读的问题了。

Transaction A Transaction B
MySQL隔离级别_第12张图片  
  start transaction;


insert into user(id, name, age) values (6,'麻子',35);


commit;

MySQL隔离级别_第13张图片

TransactionB提交,但是此时TransactionA没有读取到B的修改,这就是所谓可重复读

 

------------------------------------------------------华丽的分割线------------------------------------------------------------

至此验证完了可重复读,下面紧接着就出现了幻读~

 

MySQL隔离级别_第14张图片

此时在TransactionA中执行insert into user(id, name, age) values (6,'麻子',35);出现错误

但是在华丽的分割线的上面,查询语句是没有查到有id为6的记录的

 
   


10.测试Serializable

set global tx_isolation='serializable';
set session tx_isolation='serializable';

设置隔离级别为Serializable后,就不会出现幻读的问题了。

在这种情况下,只允许一个事务在执行,其它事务必须等待这个事务执行完后才能执行。没有并发,只是单纯的串行。

你可能感兴趣的:(MySQL,MySQL事物隔离,serializable,read-committed,repeatable-read)