1. 事务的隔离性

之所以要引入事务的不同隔离级别,其实还是为了提升单个事务单元的并发能力。多个事务之间通过锁分离可以提升多个事务单元的并行能力:

这里推荐一篇好文:拨开云雾见天日:剖析单机事务原理

1.1 事务隔离性强弱

事务的隔离级别从弱到强(严格)依次为:

Read Uncommitted->Read Committed->Repeatable Read->Serializable

隔离级别越强,事务并发能力越差,但是出现的问题(脏读、幻读、不可重复读等)越少。

1.2 讨论不同事务隔离级别时会出现的问题

较低的隔离级别会带来以下的问题:

  1. 脏读(Dirty Read):一个事务单元A的读操作读到了另一个未提交的事务单元B写入的数据。
  2. 不可重复读取(Non-Repeatable Read): 一个事务单元中两次读同一行数据,这两次读到的数据不一样。
  3. 幻读(Phantom Read):幻读主要指1个事务单元重复执行两次结果不同。存在不可重复读的问题一般也必然存在幻读问题了。
  4. 更新丢失:两个事务单元都同时更新一行数据,一个事务单元对数据的更新把另一个事务单元对数据的更新覆盖了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。

1.3 一个事务单元内的读写并行操作:

  1. 读读并行
  2. 读写并行
  3. 写读并行
  4. 写写并行

读写操作和写读操作的区别:

  1. 读写并行:先进行读,后来又来了写操作,一起并行就是读写操作。入下图所示

  1. 写读并行:先进行写,后来来了读操作,一起并行就是写读并行。

2. 读未提交(read uncommitted)

理解重点:

  1. 隔离性最低
  2. 只加写锁不加读锁(所有事务都可以看到其他未提交事务的执行结果)。没有读锁意味着读写并行和写读并行都是可以的。
  3. 存在不可重复读、幻读、脏读问题
  4. 由于压根没有读锁,所以支持读读并行、读写并行、写读并行

3. 读提交( Read Committed)

  1. 发生写读并行的情况,将读锁升级为写锁,当前写操作可以加入之前的读操作一起并行执行
  2. 支持读读并行,读写并行(可以将后来的1个写操作和多个读操作并行,利用读锁升级)。
  3. 仍然存在幻读和不可重复读的情况。
  4. 脏读问题通过引入读锁解决。引入读锁就不存之前说的写读并行的问题。已经在写的行已经上锁,后来的读操作不能读取正在被写的数据行。

区别读未提交,解决脏读的关键是加入了读锁。

4.可重读( Repeatable Read)

  1. 只能读并行
  2. 因为包含完整的读写锁,所以不会发生不可重复读的问题。也就是说读并行的时候是没有其他并行的写操作干扰的。
  3. 仍然存在幻读的问题。因为别的事务单元的操作仍然会对现有事务单元造成干扰。

PS:幻读的问题通过基于MVCC的快照读来解决

5. 串行(Serializable)

最强隔离性,没有任何并行。并发性能最差,也没有任何脏读、幻读、不可重复读的问题。