mysql事务隔离级别/脏读/不可重复读/幻读详解

1、四种事务隔离级别mysql

1.1 read uncommitted 读未提交sql

即:事务A能够读取到事务B已修改但未提交的数据。session

除非是文章阅读量,每次+1这种无关痛痒的场景,通常业务系统没有人会使用该事务隔离级别,标准实在太宽松了。并发

 

1.2 read committed 读已提交(简称RC)分布式

即:事务A只能读取到事务B修改并已提交的数据。性能

这个级别相对要严格一些,至少是要等其它事务把变动提交到db,才能读取到,听上去蛮靠谱的。可是有些业务场景,好比会员系统中,若是要在一个事务中,屡次读取用户身份,判断是否会员,若是刚开始读取到该用户是会员,作了一些逻辑处理,后面又读到用户不是会员了,这就有点崩溃,不知道如何继续。这种但愿同1个事务中,关键数据无论读取屡次次,结果都同样,RC级别就不行了。测试


1.3 repeatable read 可重复读spa

即:同一个事务中,屡次读取某一行记录,始终是同样的值,无论在此期间,其它事务有没有修改过该数据(不管是否提交)。该级别解决了RC不可重复读的问题,可是存在幻读问题(幻读后面会详解)。code

 

1.4 serializable 串行化blog

即:一个事务在修改其它数据时,若是有其它事务也想改,必须等前面的事务提交或回滚后,才能继续。最严格的级别,可是性能最低,也几乎没人用。

 

2、脏读/不可重复读/幻读
2.1 脏读

 

验证:

a. 找一个mysql环境,建一个测试表t_people,就2列 id ,name

b. 开二个mysql终端,连到db上,为方便讲解,这2个终端称为“终端1”、“终端2”,终端1里输入:

set session transaction isolation level read uncommitted;
start transaction;

即:设置当前会话的隔离级别为"读未提交"。

终端2里,输入:

start transaction;
update t_people set name='xxx' where id=1;

而后再回到“终端1”,执行 

select id,name from t_people where id=1;

能够看到,读取到了未提交的脏数据 。 终端2里,此时若是执行rollback回滚 

终端1里,继续执行

select id,name from t_people where id=1;

能够发现最新结果,已是回滚后的数据。很显然:若是有脏读问题出现,就更加保证不了“可重复读”。

 

2.2 不可重复读

 

将事务隔离级别设置成read committed(即:读已提交),可解决脏读问题,但知足不了“可重复读需求”。

验证方法跟刚才相似,终端1里输入:

set session transaction isolation level read committed;

将级别设置成RC,而后2个终端里都开启事务,终端2中,修改一行数据,可是不提交,此时终端1里应该是读不到终端2修改的数据。而后终端2提交,终端1才能读到修改后的数据。终端2若是继续修改、提交,终端1里再读取这1行,将是最新的值。(也就是只说,只要终端2不断修改,不断提交,终端1里就能读到这行不一样的新值,即:保证不了同1个事务中,同一行数据,屡次重复读取的值不变)

 

2.3 幻读

将隔离级别继续调整至Repeatable Read,仍是刚才的场景,变成这样:

 

事务A对于同一行数据,无论读多少次,始终是相同的值,彻底不理会有没有其它事务在修改它。有点:“两耳不闻窗外事,一心只读圣贤书”的味道。可是这也有问题,好比秒杀订单系统中,事务A第1次读取商品库存,发现还有1个,能够下单,赶忙继续,可是此时,可能有另外一个事务,也在下单,已经提交了订单,把库存减为0了,事务A并不知道,由于屡次读取库存的值是同样的,仍是1,最后仍然把订单建立了,造成超卖。

验证方法:

set session transaction isolation level repeatable read;

剩下的步骤跟前面相似,就不重复赘述了。 

 

2.4 串行化

从db层面,要想同时解决脏读、不可重复读、幻读,只有串行化这个级别能够作到。

set session transaction isolation level serializable;

以下图:终端1设置串行化后,紧接着select xxx where id=1这条语句后,id=1的这行记录,就被锁了。

在终端2里,更新其它记录(即:id不等于1)能够正常成功,可是更新id=1 时,就会卡住,除非终端1把事务提交或回滚,不然将一直卡着,直到超时失败。

 

小结

隔离级别   存在的问题
读未提交    脏读、不可重复读、幻读
读已提交   不可重复读、幻读
可重复读 幻读
串行化 性能问题

隔离级别越严格,db综合性能越低。

 

建议:

大多数状况下,RC(读已提交)基本上就足够了,若是并发度高,能够考虑“RC级别+(应用层)分布式锁”,这样即能保证数据正确,对db的性能压力也较低。