天天看点

事务的隔离级别?幻读和不可重复的区别

文章目录

        • 一 定义
        • 二 解释
          • Read-Uncommited(读未提交)
          • Read-commited(读已提交)
          • Repeatable-Read(可重复读)
          • Serializable(串行化)
        • 三 什么是不可重复读,什么是幻读
          • 不可重复读
          • 幻读

一 定义

mysql的事务隔离级别一共有四个:

  • 读未提交(Read-Uncommited),
  • 读已提交(Read-Commited),
  • 可重复读(Repeatable-Read) ,
  • 串行化(Serializable) 。

其中,MySQL的默认的事务隔离级别为可重复读(Repeatable-Read)。

二 解释

简单的介绍一下四种隔离级别:

Read-Uncommited(读未提交)

在Read Uncommited级别,事务中的修改,即便没有提交,对其他事务也都是可见的,事务可以读取未提交的数据,这也是被叫做脏读(Dirty Read),这种级别会导致很多问题,从性能上看,Read Uncommited不会比其他的级别好太多,但缺乏其他事务级别的很多好处,除非真的非常有必要的理由,在实际应用中,一般最好不要使用

Read-commited(读已提交)

大多数数据库系统的默认隔离级别都是Read Commited(Oracle,但是Mysql不是),Read Commited满足事务隔离级别的一般定义,一个事务开始时,只能看到已经提交的事务所做的修改,换句话说,一个事务从开始到提交之前,所做的任何修改对其他事务都是不可见的,这种级别有时候也叫不可重复读,因为两次执行同样的查询,可能会得到不一样的结果。

Repeatable-Read(可重复读)

Repeatable-Read解决了脏读的问题,该级别保证了在同一个事务中多次读取同样记录的结果是一致的,但是理论上,可重复读隔离级别还是无法解决另一种幻读(Phantom Read)的问题,所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会出现幻行(Phantom Row),Innodb和XtraDB存储引擎通过多版本并发控制(MVCC ,multuversion concurrencyControl)解决了幻读的问题,

该级别是Mysql的默认的事务隔离级别

Serializable(串行化)

Serializable是最高的隔离级别,它通过强制事务串行执行,避免了前面说的幻读问题,简单来说,Serializable会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁竞争的问题,实际应用中也是很少使用到这种隔离级别,只有在非常需要保证数据的一致性而且可以接收没有并发的情况下,才考虑使用该事务的隔离级别。

三 什么是不可重复读,什么是幻读

在去实际区分这两个定义之前,我们先去了解一下定义:

  • 脏读(Diry Read)实际上在上面个的定义中,已经说明:事务中的修改,即便没有提交,对其他事务也都是可见的,事务可以读取未提交的数据,这也是被叫做脏读
  • 不可重复读:同一事务的两次同样的操作执行,会的到不同的结果
  • 幻读:指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会出现幻行
不可重复读

查看mysql当前默认的事务隔离级别:

# 表示查询当前会话的事务隔离级别
select @@tx_isolation;
# 表示查询当前全局范围内mysql的事务隔离级别
select @@global.tx_isolation;
           
事务的隔离级别?幻读和不可重复的区别

1,首先演示,设置当前全局mysql的事务隔离级别为读已提交(Read-commited)

//设置read uncommitted级别:
set session transaction isolation level read uncommitted;

//设置read committed级别:
set session transaction isolation level read committed;

//设置repeatable read级别:
set session transaction isolation level repeatable read;

//设置serializable级别:
set session transaction isolation level serializable;
           

2,设置事务手动提交,并且在事务A中第一次查询user_info表的school字段数据,然后再B事务中修改user_info表中的school字段数据,同时提交事务,这个时候再在A事务中查询user_info表中的school字段数据,会发现两次同样的查询语句对应的结果不一致

A事务:

事务的隔离级别?幻读和不可重复的区别

B事务:

事务的隔离级别?幻读和不可重复的区别
幻读

1,修改mysql的事务隔离级别为可重复读,同样执行上面的操作,

A事务:

事务的隔离级别?幻读和不可重复的区别

B事务:

事务的隔离级别?幻读和不可重复的区别

此时我们会发现REPEATABLE-READ事务隔离级别是解决了不可重复读,即A事务中,同样的执行语句无论B事务是否对其进行修改并提交事务,A事务中的查询语句结果都是一致的。

注:在《高性能Mysql》一书中,关于什么是幻读进行了这样的讲解:

事务的隔离级别?幻读和不可重复的区别

所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。InnoDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。

但是:RR的事务隔离级别并没有解决另一种通常意义上说的也是幻读现象,那就是insert的情况

举例:

对于A事务,我们查询user_info表中没有对应的浙江大学的school,对于B事务,我们任然在事务中查询不到对应的浙江大学的school,这个时候,我们在A事务中首先创建了一个school为浙江大学的一列数据并提交事务,此时B事务中根据REPEATABLE-READ事务隔离级别任然是不会查询到school为浙江大学的一列数据,这个时候我们再在B事务中插入一个school为浙江大学的一列,因为我们在school字段加了唯一索引,这个时候就会出现B事务插入shcool数据重复的问题:

A事务

事务的隔离级别?幻读和不可重复的区别

B事务:

事务的隔离级别?幻读和不可重复的区别