read uncommitted(未提交读)
在read uncommitted级别,事务中的修改,即使没有提交,对其他事务也都是可见的,事务可以读取未提交的数据,这也被称为脏读,这个级别会导致很多的问题,从性能上说,read uncommitted不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的非常有必要的理由,实际应用中一般很少用到。
read committed(提交读)
大多数数据库系统的默认隔离级别都是read committed(但mysql不是的),read committed满足前面的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改,换句话说,一个事务从开始到提交之前,所做的任何修改对其他的事务是不可见的,这个级别有时候也叫作不可重复读,因为两次执行同样的查询,可能会得到不一样的结果
repeatable read(可重复读)
repeatable read 解决了脏读的问题,该级别保证了同一个事务中多次读取同样记录的结果是一致的,但是理论上,可重复读隔离级别还是无法解决另外一个幻读的问题,所谓幻读,指的是当某个事物在读取该范围的记录时,会产生幻行,InnoDB和XtraDB存储引擎通过多版本的并发控制(MVCC)来解决幻读问题。
serializable(可串行化)
serializable是最高的隔离级别,他通过强制事物串行执行,避免了前面说的幻读问题,简单来说,serializable会在读取的每一行数据上都加上锁,所以可能导致大量的超时和帧争用问题,所以实际应用中也很少用到这种隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别
四种隔离级别
隔离级别 |
脏读可能性 |
不可重复读可能性 |
幻读可能性 |
加锁读可能性 |
Read uncommitted |
Yes |
Yes |
Yes |
No |
Read committed |
No |
Yes |
Yes |
No |
Repeatable read |
No |
No |
Yes |
No |
Serializable |
No |
No |
No |
Yes |
多版本并发控制(MVCC)
可以认为MVCC是行级锁的一个变种,但是他在很多情况下避免了加锁操作,因此开销更低,虽然实现机制有所不同,但都实现了非阻塞的读操作,写操作也只锁定必要的行。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的,也就是说,不管需要执行多长时间,每个事务看到的数据是一致的。更具事务的开始时间不同,每个事物对同一张表,同一时刻看到的数据就可能不一样。
MVCC典型的实现有乐观并发控制和悲观并发控制,下面通过InnoDB的简化版行为来说明MVCC是如何工作的。
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,
一个·保存了行的创建时间
一个保存了行的过期时间(或删除时间)
存储的并不是实际时间,而是系统版本号,没开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的版本号,用来和查询到每行记录的版本号进行比较,下面看一下repeatable read隔离级别下,MVCC是如何操作的
select
InnoDB会根据以下两个条件检查每行记录:
a.InnoDB只查找版本早于当前事务的数据行,这样可以确保事务读取的行,要么是在事务开始抢就已经存在,要么就是事务自身插入或者修改过的
b.行的删除版本要么未定义,要么大于当前事务的版本号,这可以确保事务读取到的行,在事务开始前被删除
只有符合上述两个条件的,才能返回作为查询结果
insert
InnoDB为新插入的每一行保存当前系统版本号作为行版本号
delete
InnoDB为删除的每一行保存当前系统版本号作为行删除表示
update
InnoDB未插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识
MVCC只有在repeatable read 和Read committed两个隔离级别下工作,其他两个隔离级别都和MVCC不兼容,因为Read uncommitted总是读取最新的数行,而不是符合当前版本的数据行,而serializable则会对所有读取的行都加锁