SQL标准定义的隔离级别
一、未提交读(READ UNCOMMITED)
此事务中,A事务还未提交的修改可被B事务读取到,称为脏读(Dirty Read),与脏数据不同;一般很少使用此隔离级别(性能并未有显著优势,且问题较多)
二、提交读(不可重复读)(READ COMMITED)
大部分数据库的默认隔离级别,B事务只能读取A事务中已提交的数据。例如:
1、A事务开启,读取表a记录1
2、B事务开启,并修改表a记录1,提交
3、A事务重新查询表a记录1,已经是事务B中修改后的结果
一般指两次查询会有不同结果,所以也称为不可重复读(一般针对update场景)
解决问题:脏读
三、可重复读(REPEATABLE READ)
Mysql的默认隔离级别,A事务只能读取到在A事务开启之前,其他事务已提交的数据。例如:
1、A事务开启,读取表a记录1
2、B事务开启,对表a记录1进行修改并提交
3、A事务重新读取表a记录1,仍然是一样的数据,并未读取到B事务中的修改
解决问题:不可重复读
未解决问题:幻读(实际上一般会通过MVCC,Multiversion Concurrency Control,即多版本并发控制解决)
ps:幻读-一般指在插入新数据的场景下(针对insert场景):
1、A事务开启,读取表1,ID大于3的记录,此时有2条
2、B事务开启,插入1条ID为11的记录到表1,并提交
3、A事务重新读取表1,ID大于3的记录,此时有3条。
MVVC:只在提交读和不可重复读隔离级别中使用,通常用悲观锁和乐观锁实现【基于并发场景】
* 悲观锁,一般对共享资源上锁,容易造成死锁和较长的等待时间
* 乐观锁,通常引入版本号概念,通过比对版本号来确定操作是否能够成功。并不上锁,一般情况下多条并发处理,只会有一条成功。
四、可串行化(SERIALIZABLE)
最高的隔离级别。会强制事务串行执行,简单来说,会在读取(读锁)的每一行数据上都加锁,一般来说在多线程场景下,性能低下。
解决问题:幻读
隔离级别 | 脏读 | 不可重复读 | 幻读 |
未提交读 | √ | √ | √ |
提交读 | χ | √ | √ |
可重复读 | χ | χ | √ |
可串行化 | χ | χ | χ |
mysql默认的隔离级别是可重复读,一般我们也是选择这个隔离级别
原因:如上表格,可重复读解决了脏读和可重复读的问题,而一般又采用了MVVC多版本并发控制来解决幻读的问题,所以在效率和ACID综合考虑下是相对较好的一个隔离级别选择
oracle默认是不可重复读