1、 ANSI SQL给出了四种标准的事务隔离级别:可序列化(Serializable)、可重复读(Repeatable reads)、提交读(Read committed)和未提交读(Read uncommitted)。
还有一个Snapshot的概念。
2、 隔离级别只会影响读操作申请的共享锁,而不会影响写操作的互斥锁。
3、 隔离级别影响读事务的行为:
1) 否使用共享锁,以哪种隔离级别来隔离。
2) 事务持有读锁的时间
3) 在有其他更新事务进行数据操作时,如何执行读的操作。
l 被阻塞,等待其他事务释放互斥锁
l 读取事务提交后的版本,该数据行在事务开始时存在
l 读没有提交的数据
下面介绍不同隔离级别下的差异
4、 隔离级别:ReadCommitted(意思是只能读到Commited的数据)
大多数数据库默认的隔离模式(有说MySQL不是,不知指哪个存储引擎)。在事务完成提交之前,其他事务看不到该事务的修改结果。但可能的是:如果一个事务A中读2次数据。而在此中间,有另外事务B修改相关数据并提交,则在A的两次读中,值不一样。所以也叫做不可重复读。但确保的读到的数据,一定是Commit的。
这里还加上Snapshot后,行为有不同。
1) 如果Snapshot为OFF,读操作申请共享锁,阻塞其他事务的写操作。一旦读操作完成,释放共享锁。
2) 如果Snapshot为ON,读操作时使用RowVersioning(这实际就是Snapshot的概念),就是有多副本,写操作不阻塞读操作,所以不会申请共享锁,不会阻塞其他事务的写操作。
5、 在ReadunCommited下
1) 读操作不会申请SharedLock。因此读操作不会阻塞写操作。事务中的修改及时没提交也会被其他事务可见,这样会产生脏读,如果事务失败回滚,则其他事务之前的到的数据则是脏数据。从性能上讲,不会别别的事务提高太多,但是极其不安全。
6、 在Repeatablereads下
事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。事务A再读取时,却发现数据发生了变化。造成了幻读。(MySQL默认的隔离级别)。
另一种更好理解:事务在执行过程中可以看到其他事务已提交的新插入记录,但不能看到其他事务已提交的对已有记录的更新。
7、 在Serializable下
是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读。
在Snapshot隔离级别下,事务在修改任何数据之前,先将修改前的数据复制到tempdb,写操作创建数据行的一个原始版本(Row Version)。后续其他事务的一切读操作都去读这个复制的行版本。在Snapshot隔离级别下,读写操作不会互相阻塞。使用行版本控制提高事务的并发性,但是有一个明显的缺点,虽然用户读到的不是脏数据,但是数据可能正在被修改,很快就要过期。如果根据这个过期的数据做数据修改,可能会产生逻辑错误。
参考:
1、《数据库的快照隔离级别(Snapshot Isolation)》https://www.cnblogs.com/ljhdo/p/5037033.html