MySQL事务的隔离级别

91 阅读5分钟

参考

  1. 官方隔离级别介绍 Transaction Isolation Levels
  2. 14.7.1 InnoDB Locking
    1. share (s) 共享锁(读锁)

    2. exclusive (X) 排它锁(写锁)

    3. Intention Locks(意向锁) 指出将要对表加什么锁

      1. IS ex: SELECT ... LOCK IN SHARE MODE
      2. IX ex: SELECT ... FOR UPDATE
    4. Record Locks

    5. Gap Locks (间隙锁)

    6. Next-Key Locks (间隙锁的组合)

  3. 14.7.2.4 Locking Reads
  4. 范围锁 MySQL Glossary
  5. 凤凰架构本地事务

凤凰架构本地事务学习笔记

  1. 三种锁
  1. 写锁, 当前事务能读能写,其它事务不能读写
  2. 读锁, 其它事务能读,但不能写,如果只有一个事务加了读锁(该事务本身),可以加写锁
  3. 范围锁, 对于某个范围直接加排他锁,在这个范围内的数据不能被写入。(不能这个范围内写入数据)

意“范围不能被写入”与“一批数据不能被写入”的差别,即不要把范围锁理解成一组排他锁的集合。加了范围锁后,不仅无法修改该范围内已有的数据,也不能在该范围内新增或删除任何数据,后者是一组排他锁的集合无法做到的。

  1. 四种隔离级别(由高到低)
  1. 串行化: 对事务所有读、写的数据全都加上读锁、写锁和范围锁
  2. 可重复读: 对事务所有读、写的数据全都加上读、写锁,并且一直持有到事务结束
  3. 读提交: 对事务所有读、写的数据全都加上读、写锁,写锁一直持有到事务结束,读锁查询结束立刻提交
  4. 读示提交: 对事务写的数据全都加上写锁,写锁一直持有到事务结束,读根本不锁

为什么忙着释放读锁?

当然是为了并发时的性能!!!

MVCC 是对 “读+写”锁场景下一优化

四种隔离级别有一个共同特点,可重复读、脏读等问题都是由于一个事务在读数据过程中,受另外一个写数据的事务影响而破坏了隔离性。

针对这种“一个事务读+另一个事务写”的隔离问题,近年来有一种名为“多版本并发控制”(Multi-Version Concurrency Control,MVCC)的无锁优化方案被主流的商业数据库广泛采用。MVCC 是一种读取优化策略,它的“无锁”是特指读取时不需要加锁。MVCC 的基本思路是对数据库的任何修改都不会直接覆盖之前的数据,而是产生一个新版副本与老版本共存,以此达到读取时可以完全不加锁的目的。在这句话中,“版本”是个关键词,你不妨将版本理解为数据库中每一行记录都存在两个看不见的字段:CREATE_VERSION 和 DELETE_VERSION,这两个字段记录的值都是事务 ID,事务 ID 是一个全局严格递增的数值,然后根据以下规则写入数据。

  • 插入数据时:CREATE_VERSION 记录插入数据的事务 ID,DELETE_VERSION 为空。
  • 删除数据时:DELETE_VERSION 记录删除数据的事务 ID,CREATE_VERSION 为空。
  • 修改数据时:将修改数据视为“删除旧数据,插入新数据”的组合,即先将原有数据复制一份,原有数据的 DELETE_VERSION 记录修改数据的事务 ID,CREATE_VERSION 为空。复制出来的新数据的 CREATE_VERSION 记录修改数据的事务 ID,DELETE_VERSION 为空。

此时,如有另外一个事务要读取这些发生了变化的数据,将根据隔离级别来决定到底应该读取哪个版本的数据。

  • 隔离级别是可重复读:总是读取 CREATE_VERSION 小于或等于当前事务 ID 的记录,在这个前提下,如果数据仍有多个版本,则取最新(事务 ID 最大)的。
  • 隔离级别是读已提交:总是取最新的版本即可,即最近被 Commit 的那个版本的数据记录。

另外两个隔离级别都没有必要用到 MVCC,因为读未提交直接修改原始数据即可,其他事务查看数据的时候立刻可以看到,根本无须版本字段。可串行化本来的语义就是要阻塞其他事务的读取操作,而 MVCC 是做读取时无锁优化的,自然就不会放到一起用。

总结

事务的隔离级别

彻底搞懂 MySQL 事务的隔离级别

事务并发可能出来的情况

  1. 脏读 : 一个事务读到了另一个未提交事务修改过的数据
  2. 不可重复读 : 一个事务只能读到另一个已提交的事务修改过的数据,并且其他事务对该数据进行一次修改并提交后,该事务都能查询得到最新值
  3. 幻读 : A事务先根据某些条件查询出一些记录,之后B又向表中插入了符合条件的记录,A再次按照该条件查询时,不能把B事务插入的记录读出来,B事务依据此查询写入记录时,如果和B插入的记录一致,会存在冲突(因为B已经插入过了,由于数据库主键约束或者其它原因导致的相同记录不能插入两行)。

事务的隔离级别

下表隔离级别由上到下逐渐升高,级别越低,事务请求的锁越少

事务的隔离级别脏读不可重复读幻读
读未提交
读已提交×
可重复读××
串行化×××

MySQL默认是 可重复读