mysql有4种事务隔离级别,分别为:read uncommited(读未提交数据)
read commited(读已提交数据) ,repeatable read(可重复读) 和 serializable(串行化)。其默认隔离级别为为repeatable read。这些隔离级别是为了解决同时运行多个事务时,当这些事务访问数据库中相同的数据时引发的并发问题。一般有三种:脏读,不可重复读幻读,在下面对应的隔离级别中会 解释这些问题。并且随着隔离级别的升级,会慢慢解决这些并发问题。

设置隔离级别:set session transaction isolation level 隔离级别
查看当前隔离级别:select @@tx_isolation

①隔离级别为read uncommitted,啥都解决不了

如图,我设置当前隔离级别为read uncommited,这是最低级别的隔离。意思是在事务中做了update,insert或者delete操作,事务未提交时,在另外一个窗口查看该表,可以得到实时数据更新。
MYSQL事务隔离级别
接下来我往表中插入数据,字段为id和money,插入3条数据
MYSQL事务隔离级别
接下来我开启事务,并将 A的money从100更新为150,C的money从300更新到250 (id,money为字段名)。但是,我此时并未rollback或者commit,也就是我处于未提交状态
MYSQL事务隔离级别
那么,我新开了一个窗口,同样操作,开启一个新的事务,并设置相同的隔离级别,注意:这个很重要,如果没有设置相同的隔离级别,就无法实现。
MYSQL事务隔离级别
可以看到,我在另一个窗口查看未提交的事务中所做的改变,可以得到相同的结果,也就是说:read uncommited隔离级别就如字面意思,可读取未提交的数据。顺带提一下,这种情况也称为 脏读,意思是对于两个事务t1,t2,当t1去读取已经被t2更新但是却未提交的数据时,可以读取到,若此时t2回滚,t1读取到的就是无效的。比如下图,我执行回滚,然后再去另一个窗口查看:
MYSQL事务隔离级别
另一个窗口的事务:
MYSQL事务隔离级别
很明显,再次读取时,money并未改变,因为我已经rollback了,所以这些update操作是无效的。 注意:这种隔离级别是最低的,会出现很多并发问题。

②隔离级别为read committed,解决脏读

意思是读已提交的数据,同样从字面意思理解:就是当事务发生update,insert或者delete操作,但还未提交的时候,另一个事务去读取这个表的数据,是无法读取实时更新的数据的。
如下图,还是干一样的事情,把A的money更新成150,C的money更新成250,然后我先不提交,在另一个窗口来读取这个表,看看能不能得到新的A的money和新的C的money
MYSQL事务隔离级别
另一个窗口如下,很明显,我还没提交事务,且隔离级别为read committed,所以读不到更新后的,也就是解决了“脏读”问题。
MYSQL事务隔离级别
接下来我commit一下,看看结果是不是可以读到更新,很明显可以了。
MYSQL事务隔离级别
另一个窗口的事务:
MYSQL事务隔离级别
总结一下:上面这种情况叫做不可重复读,其定义为:对于t1,t2两个事务,t1去读取已经被t2更新了但是还没提交的数据,得到一个值,然后t2提交后,t1再去读同一个数据,又得到一个值,这两个值是不同的。
那我们要解决“不可重复读”的问题,就需要继续升级隔离级别,看下面。

③ 隔离级别为repeatable read,解决脏读,不可重复读

意思是可重复读,如下图,我把A的money更新成1000,并在另一个窗口的事务来查看。
MYSQL事务隔离级别
可以发现我还没提交之前,没有出现“脏读”情况,money并未改变。
MYSQL事务隔离级别
接下来我在第一个事务那里commit,然后在另一个窗口中的事务继续查看,发现还是没改变,这就解决了“不可重复读”问题
MYSQL事务隔离级别
接下来我把另一个窗口的事务也提交了,再次查询可以发现money已经改变了,这就是 隔离级别为repeatable read(可重复读),可以解决脏读、不可重复读问题。
MYSQL事务隔离级别

④隔离级别为serializable(串行化)。啥都能解决,但是效率低

幻读:对于两个事务t1和t2,t1从一个表中读取一个字段,然后t2在该表中插入一些新的行并且提交之后,如果t1再次读取同一个表就会多出新增的行。
比如下图,我开启一个事务,并打算将所有money设置为300,我的表只有3行数据。
然后同样的,我在另一个窗口开启一个新事务,然后新增一行数据。
MYSQL事务隔离级别
需要注意:如果隔离级别是serializable,当在事务1中进行update操作,并且还未提交的时候,在另一个事务2中做insert操作,会阻塞在insert语句。如果隔离级别不是serializable而出现“幻读”,那么这个时候左图的update执行完后,显示的应该是Change:4。
而现在我设置隔离级别是serializable,就解决了“幻读“的问题。
MYSQL事务隔离级别
总结一下:对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,会导致各种并发问题,比如上面提到的 脏读、不可重复读、幻读等等。举个例子,说两个事务并发执行,访问同一块数据,当事务1想要update,事务2想要insert,好的情况就是事务1干完update就提交,只有事务1提交完了,事务2才可以insert。这样避免上面提到的三种并发问题,而只有最高级别的serializable才可以做到,而且因为存在阻塞,所以效率并不高。也因此mysql的默认隔离级别是第三种repeatable read

相关文章: