首先说读未提交,它是性能最好的,也可以说它是最野蛮的方式,因为它压根儿就不加锁,所以根本谈不上什么隔离效果,可以理解为没有隔离。
再来说串行化。读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。
最后说读提交和可重复读。这两种隔离级别是比较复杂的,既要允许一定的并发,又要兼顾解决问题。
实现可重复读取
为了解决不可重复读,或者为了实现可重复读,MySQL 采用了 MVVC(多版本并发控制)的方式。
我们在数据库表中看到的一行记录可能实际上有多个版本,每个版本的记录除了有数据本身外,还要有一个表示版本的字段,记为 row trx_id ,而这个字段就是使产生的事务 id ,事务 id 记为 transaction id ,它在事务开始的时候向事务系统申请,按时间先后顺序递增。
按照下图理解,一行记录现在有 3 个版本,每一个版本都记录这使其产生的事务 ID ,比如事务A的 transaction id 是 100 ,那么版本1的 row trx_id 就是 100 ,同理版本 2 和版本 3 。
读提交和可重复读都有快照,学名叫做一致性视图,这也是可重复读和不可重复读的关键,可重复读是在事务开始的时候生成一个当前事务全局性的快照,而读提交则是每次执行语句的时候都重新生成一次快照。
对于一个快照来说,它能够读到哪些版本数据,要遵循以下规则:
- 当前事务内的更新,可以读到;
- 版本未提交,不能读到;
- 版本已提交,但是却在快照创建后提交的,不能读到;
- 版本已提交,且是在快照创建前提交的,可以读到;
还是要强调,两者主要的区别就是在快照的创建上,可重复读仅在事务开始时创建一次,而读提交每次执行语句的时候都要重新创建一次。