飞道的博客

用sql教你什么是mysql的四种隔离级别

436人阅读  评论(0)

阅读本篇文章,首先要了解以下三个基础知识,有个大概的概念,这三个基础知识具体内容就不赘述了。

事务的基本要素

A 原子性、C 一致性、I 隔离性、D 持久性。

事务并发产生的问题

脏读,

不可重复读

幻读

mysql事务隔离级别

读未提交 RU read-uncommitted

读已提交 RC read-committed

可重复读 RR repeatable-read (mysql默认的隔离级别为 RR)

串行化 serializable

 

接下来会用sql来演示以上的内容

读未提交

事务A读取到了事务B未提交的数据。

首先,在开启两个query的窗口,都执行下面的两行sql


  
  1. -- 先执行下,可以看到mysql默认的隔离级别是RR
  2. select @@tx_isolation;
  3. -- 设定当前session的隔离级别为RU
  4. set session transaction isolation level read uncommitted;

 

在第一个窗口中执行下面的语句(注意两个窗口,都按照注释中的step一行一行执行)


  
  1. -- step 1.1 开启A事务
  2. begin;
  3. -- step 1.3 执行查询
  4. select * from account;
  5. -- step 1.5 再次执行查询,发现读取到了B事务中的更改
  6. select * from account;
  7. -- step 1.7 提交事务
  8. commit;

在第二个窗口中执行下面的语句


  
  1. -- step 1.2
  2. begin;
  3. -- step 1.4
  4. update account set balance = balance - 50 where id = 1;
  5. -- step 1.6 回滚事务
  6. rollback;

当执行到step 1.5,结果中可以看到事务A中,能查询到事务B未提交的事务。

如果后续step1.6中回滚了事务B,但是在这之前,事务A却拿着已更改的数据中间状态来处理后续的逻辑,就会造成脏读了,比如事务A也执行 balance - 50 的操作。那么最终的结果,id为1的数据从最开始的450变成了350,但是实际两个事务最终要的结果是只减少50.

以上就说明了,在RU隔离级别下,事务A能读取到事务B未提交的数据,导致了脏读。

 

读已提交

读已提交就是为了解决读未提交脏读的问题

修改两个query session的隔离级别为读已提交


  
  1. -- 先执行下,可以看到mysql默认的隔离级别是RR
  2. select @@tx_isolation;
  3. -- 设定当前session的隔离级别为RC
  4. set session transaction isolation level read committed;

在两个窗口中,都开启事务 begin; 然后按照一下的顺序执行:

事务A开启事务后,执行查询语句,此时数据为450

事务B中,执行更新

事务A中再次执行查询,会发现数据仍为450,这就表示没有出现上面读未提交隔离级别中,读到事务B未提交的数据的情况

事务A执行更新,此时会发现执行阻塞了,因为此时事务B的更新操作,并没有提交,事务A获取不到锁

事务B一直不提交,那么事务A最终会锁超时,如下图所示

事务A的更新操作在执行过程中等待锁,这个时候事务B回滚事务,那么事务A会立即执行完成,最终结果id=1的数据balance是400。这样就说明了不会出现脏读导致的脏数据问题。

读已提交,解决了脏读的问题,但是会出现如下不可重复读的问题

事务A开启了事务,进行了一次查询此时的数据,仍旧是450。

然后,事务B开启了事务并且更新数据为400直接提交事务B。

事务A再次查询,就会发现数据已经变为了400。 

在同一个事务A中,两次查询得到了不同的数据,这就是不可重复读的问题。

可重复读

可重复读就是来解决读已提交中的不可重复读的问题,保证在同一个事务中读取到的数据是一致的。

修改一下隔离级别


  
  1. -- 先执行下,可以看到mysql默认的隔离级别是RR
  2. select @@tx_isolation;
  3. -- 设定当前session的隔离级别为RR
  4. set session transaction isolation level repeatable read ;

在事务A中,开启事务并查询,此时数据为300,也就生成了一份数据快照

在事务B中,开始事务并更新数据为350,提交事务

事务A中再次执行查询,发现数据仍为300,读取的仍旧是快照当中的内容,可以证明可重复读,解决了不可重复读的问题。

此时不要提交事务A,再开启事务B并且删除id=3的数据并提交事务

这个时候,事务A再次查询还是能够看到id=3的数据

此时,事务A仍旧没有提交,刚才在事务B中已经将id=1的数据更新为350并提交了,此时在事务A中,执行将id=1的数据 + 50,再次查询数据,会发现id=1的数据变成了400,这样数据的一致性就没有被破坏,原因是因为可重复度的隔离级别下,使用了MVCC机制,select操作是快照读,insert/update/delete是当前读。

 

但是,可重复读中会出现幻读的问题:

在开启事务A,查询

在事务B中,插入数据并提交

在事务A中查询,仍旧看不到lucy这条数据,但是执行插入id=4的数据,会报主键冲突,这也就是幻读的现象

幻读和不可重复读很容易混淆,只要记住不可重复读是针对修改和删除的,幻读是针对新增的即可。

如果你觉得这篇文章对你有帮助,请点击下方,一键三连


转载:https://blog.csdn.net/u010372981/article/details/108654950
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场