MySQL事务的隔离性

2019-02-01  本文已影响0人  weigs

什么是事务的隔离级别

事务的隔离级别,老生常谈的问题了,指多个事务并发执行的时候相互之间不受到彼此的干扰,根据隔离程度对隔离性有会分类。在具体介绍事务隔离性前有必要介绍几个名词说明数据库并发操作存在的问题。

脏读

事务可以读取未提交的数据,就被称为脏读。 -------《高性能MySQL》

从定义来看,这个很好理解,举个例子来说:假如有两个事务AB同时更新一个数据c=1,事务A执行select语句获取到c=1,然后事务A将数据更改为c=2但是没有提交事务。这时候事务B执行select发现此时的数据为c=2,这样就产生了脏读。

不可重复读

事务在提交前可以看到其他事务已经提交的数据,导致两次读取出现不一样的结果,我们称之为脏读

同样举例来说明这种数据出现的情况:两个事务AB,事务A执行select操作查询出数据d=1,此时事务B将此数据更改为d=2并提交了事务,此时事务A再执行select操作时,发现数据d=2和上一次查询的结果不一样,这就导致了数据的不可重复读。

幻读

所谓幻读,是指当某个事务在读取某个范围内的记录时,另外一个事务又在改范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。 --《高性能MySQL》

上面的定义是我们理解中的定义,大部分人都是这么理解幻读,然而幻读真的是如此的吗?后面介绍隔离性的时候我们会在实际操作中验证这点。

事务的隔离级别

Read Uncommited

未提交读隔离级别,就是指一个事务中可以读取其他事务未提交的数据,这个级别会导致脏读。下面在我本机安装的mysql中验证这一点;

mysql的默认隔离级别是Repeatable Read,如下图所示:

image.png
下面我们把隔离级别改为Read Uncommited:
image.png
image.png
下面验证此隔离级别下会出现的脏读情况,打开两个终端
终端一:开启事务,查询test表中的数据,结果如下
image.png

终端二:开启事务,往test表中插入数据,但是不提交事务,结果如下

image.png

终端一:终端二插入数据以后往在终端一中执行同样的查询语句,结果如下


image.png

然后将终端二中的事务回滚,此时在终端一中的事务中查询数据,发现刚才插入的数据又消失了
终端二:


image.png

终端一:


image.png

从上图发现,在终端二中的事务没有提交的情况下,终端一中的事务就能够读取到插入的数据,所以在 read-uncommitted隔离条件下就会产生脏读的情况。这个隔离级别是最低的隔离级别,上面所说的脏读、不可重复读和幻读等情况都会出现,所以一般来说不使用此隔离级别。

Read Committed

提交读隔离级别,一个事务开始时,只能读取到已经提交的事务所做的修改。这个隔离级别会出现不可重复读的情况
修改数据库的事务隔离级别为Read Committed:

image.png

终端一:


image.png

终端二:

image.png
终端一:
image.png
从上面两个终端的截图发现,终端二中的事务在没有提交事务的情况下,修改的数据在终端一中是查询不到的,提交事务,再查看结果
终端二:
image.png
终端一:
image.png
从上面结果看出,终端二中的事务提交以后,在终端一中可以查询出结果。
该隔离级别下面会出现不可重复读和幻读的情况,但是不会出现脏读的情况,oracle的默认隔离级别就是提交读的隔离级别。

Repeatable Read

可重复读隔离级别,保证同一个事务在多次读取同样的结果中是一致的。
修改隔离级别


image.png

我们按照《高性能MySQL》上的说法做一个实验,看看是否会出现幻读的情况:
终端一:


image.png
终端二:
image.png
image.png

终端一:


image.png

从上面来看,并没有出现幻读的情况,终端一中的数据集并没有发生改变。其实幻读不能理解成读-读的过程,而是应该理解为读-写的过程,事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前监测到的数据中多了一行,像产生幻觉一样。怎么理解上面那句话呢,下面这个例子就能很好的解释这一点:
事务一:
执行sql:
select * from test where id = 3;
执行结果为null,证明没有主键 id=3的这行数据
事务二:
执行sql:
insert into test(id,num,date) values(3,3,now());
然后提交事务二
事务一:
执行sql:
insert into test(id,num,date) values(3,3,now());
执行此 sql时发现报错,显示已经有id=3数据,就像产生幻觉,明明是没有数据,为什么突然出现这行数据呢!!!

Serializable

可串行化隔离级别,强制事务串行执行,这种隔离级别在实际使用中很少用,所以不做过多的介绍。

上一篇下一篇

猜你喜欢

热点阅读