Read-Uncommited(RU)

RU只添加了写写锁,保证修改数据和插入不会出现数据安全问题,会出现脏读,此隔离级别基本不会使用。

Read-Conmmited(RC)

RC,顾名思义,如果同时存在a和b两个事务。那么a中是没办法读到b事务未提交的修改数据的。RC修改和写入数据也是通过写写锁保证的。读操作通过MVCC实现。a事务每次在读取数据时,都会更新read_view,read_view中又存储了当前已经开启但是还未提交的事务id,因此要判断某一行数据是否可见,只需要判断数据版本对应的是事务tx-id是否在read_view中,或者tx-id>low_trx_id。RC可以避免出现脏读。

Repeatable-Read(RR)

RC数据库隔离级别下,事务中的每次查询都会更新read_view获得最新的读取视图,解决了脏读问题。但是额外带来的问题就是每次读取视图的变化,也可能导致同一个事务内对同一条数据的读取结果不一致。因此,在RR隔离级别下,每次开启事务后,read_view就不在变化,这样可以保证同一个事务内,多次读取的数据都保持一致。但是RR隔离级别仍然存在幻读现象,因为多次读的结果虽然一致,但是并不代表数据库实际的数据存储没发生变化。

MVCC并发控制中,读操作主要分为两类:1. 快照读。2. 当前读。快照读,读取的是数据的历史版本,因为版本有多份,可以提高并发量。当前读,读取的是数据的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。

以Inodb为例,哪些操作是快照读,哪些操作是当前读呢?

快照读:

select * from table where ?;

当前读:

select * from table where ? lock in share mode;

select * from table where ? for update;

insert into table values (…);

update table set ? where ?;

delete from table where ?;

因此,在RC和RR数据隔离级别下,所有的update和insert操作都属于当前读,读取数据的最新版本。当然这样还不能解决幻读问题,RR隔离级别下,同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),从而保证不存在幻读现象。

Serializable

Serializable隔离级别下,数据库不再使用MVCC并发控制,完全使用共享锁和排他锁保证数据一致性。Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。