脏读

概念

脏数据是指事务对缓冲池中行记录的修改,并且还没有被提交,就可能造成另一个事务读取到了另一个事务未提交的数据,违反了数据库的隔离性。

脏数据的读取

示例:

Mysql引擎innodb的脏读,不可重复读,幻读问题_mysql

上面示例的隔离级别换成了READ UNCOMMITTED,因此在会话A还没有提交的情况下,会话B就读到了,两次读取得到了不一样的结果,违反了事务隔离性。

但脏读的发生条件是事务的隔离级别是READ UMCOMMITTED,而mysql innodb的默认隔离级别是REPEATABEL READ,Microsoft SQL Server数据库为READ COMMITTED,Oracle数据库同样是READ COMMITTED。

mysql的事务隔离级别如下:

show variables like 'transaction_isolation%';

Mysql引擎innodb的脏读,不可重复读,幻读问题_不可重复读_02

​​Mysql 8查看并修改事务隔离级别​​

不可重复读

概念

不可重复读是指在一个事务内多次读取一个集合数据,这个事务还没有结束时,另外一个事务对这个集合数据做了DML操作,因此第一个事务中的两次读取数据之间,由于第二个事务的操作,造成了两次数据不一样,这种情况称为不可重复读。

不可重复读和脏读的区别是:脏读是读取未提交的数据,不可重复读是读取到已提交的数据,但违反了数据库事务一致性的要求。

示例

Mysql引擎innodb的脏读,不可重复读,幻读问题_不可重复读_03

示例中,会话A开启一个事务读取数据,读到一条数据,此时会话B插入了一条数据,并且提交了,随后会话A又进行了一次读取数据,读到两条,造成会话A两次读取数据记录不一致。

这个例子的前提是,事务隔离级别是READ COMMITTED。

一般来说,不可重复读是可以接受的,因为读取到的是已经提交的数据,本身不会带来很大问题,因此很多数据库都设置成READ COMMITTED隔离级别.

在innodb存储引擎中,使用next-key lock算法避免了不可重复读的问题。在mysql官方文档中将不可重复读的问题定义为Phantom problem,即幻象问题。在next-key lock 算法下,对索引的扫描,不仅锁住扫描到的索引,而且还锁住这些索引覆盖的范围。因此这个范围内都是不允许插入的。这样避免了另外的事务在这个范围内插入数据导致不可重复读的问题。因此innodb中默认事务隔离级别是READ REPEATABLE,采用next-key lock算法,避免了不可重复读的现象。

幻读

概念

指同一个事务内多次查询返回的结果集不一样(比如增加了或者减少了行记录)。比如在同一个事务A内,第一次查询时候有n条记录,但是第二次同等条件下查询却又n+1条记,这就好像产生了幻觉。

幻读是不可重复读的一种特殊场景。

上面不可重复读的例子也是一种幻读的场景,幻读可以通过gap lock解决。