虽然平时已经很少使用MySQL了,但是数据库作为基本技能仍然不能忘,最近在学习数据库隔离级别,在此写下个人理解以备复习。

大家都知道数据库事务ACID(原子性、一致性、隔离性和持久性)的四个特征,也知道数据库存在三种并发问题(脏读、不可重复读、幻读),以及针对性的四种隔离级别(读未提交、读已提交、可重复读、序列化)。

解决与否 脏读 不可重复读 幻读
读未提交 Yes Yes Yes
读已提交 No Yes Yes
可重复读 No No Yes
串行化 No No No

特别提醒一句,隔离级别作用在连接(或会话)级别。客户端每次连接数据库的时候,都要根据自己对一致性的需求程度合理设置自己的事务隔离级别。

那么问题来了,MySQL底层(下文均指InnoDB引擎)是采用何种技术来实现这四种隔离级别的呢?

读未提交

MySQL全表的数据存储在以主键为排序值的B+树索引中,叶子节点存储了相应主键的整行记录。需要指出的是,叶子节点的数据都是最新的数据,可能是事务提交后的一致状态,也可能是事务执行中的中间值(可能被回滚)。

当隔离级别设置为RU时:

  • 所有的读不加锁,读到的都是叶子节点上最新的值,性能最好。
  • 所有的写(更新、插入、删除)加行级排斥锁,不存在脏写的问题,写完就释放锁。

读已提交

当隔离级别是RC和RR时,就要谈到大名鼎鼎的MVCC(多版本控制) 技术。通过在每行加入若干隐藏的字段,它实现了不加锁的读操作,性能较好。

  • 先说RC级别的写操作,MySQL依然加行级排斥锁。事务开始时会往UNDO日志中写入当前的有效记录值,B+树叶子节点的隐藏列DATA_ROLL_PTR会存储指向该UNDO记录的指针。顺着行的DATA_ROLL_PTR的指针形成一个链表,记录该行数据的有效的历史记录。
  • 再说不加锁的读操作,如果叶子节点正被其他事务锁定,那么MySQL顺着叶子节点的DATA_ROLL_PTR指针找到上一个有效的历史记录即可。

可重复读

在事务开始的时候,除了正常往UNDO日志中写回滚的数据外,会创建一个ReadView,记录了当前活跃的其他事务的ID,其中最小值为Tmin,最大值为Tmax。

当执行SELECT操作时,MySQL顺着行记录的DATA_ROLL_PTR指针查找符合条件的历史版本。这里就用到了另一个隐藏列DATA_TRX_ID,其中存储的是更新该记录的事务ID(事务ID是全局递增且唯一的)。如果DELETE_BIT为1,则代表ID为DATA_TRX_ID的事务对当前行执行了删除。

扫描历史版本串成的链表的过滤条件是:

  1. 如果当前记录的DATA_TRX_ID小于Tmin(之前存在的数据),那么由DELETE_BIT决定是否可见;否则,转2。
  2. 如果当前记录的DATA_TRX_ID小于Tmax,且不在活跃的事务ID集合中,那么由DELETE_BIT决定是否可见视为可见;否则,转3。
  3. 否则视为不可见,顺着DATA_ROLL_PTR进入上一个历史版本,或因为到头而结束回溯。

因为插入的数据版本号要么在活跃事务ID集合内、要么小于当前事务ID,所以MVCC机制同时解决了幻读问题。

需要指出的是,以上三个隔离级别中的读均为普通的SELECT。如果用的是SELECT ... LOCK IN SHARE MODE或SELCT ... FOR UPDATE,均属于当前读。即加读锁或写锁,读叶子节点最新值。如果更早的事务改了行值,依然会存在不可重复读的情况;如果前后两次读均为当前读,则不会如此(因为第一次读加锁了)。

在RR级别下,如果WHERE的条件列上有唯一索引,那么MySQL只加行级锁;如果是普通索引,会加间隙锁来防止幻读;如果没有索引,就会首先锁表的所有记录、再释放不符合条件的行的锁,因此会大大降低并发写的能力。

串行化

读写均加表级的读写锁即可,直接读主键索引B+树的叶子节点的最新数据。该级别下,数据一致性很强,但是并发写的能力非常差。

最新文章

  1. CALayer的m34 - 三维透视效果
  2. Android教程收集贴
  3. Android应用开发-网络编程(一)(重制版)
  4. Django 浏览页面点击计数(通用视图)
  5. python文件操作实例
  6. Silverlight5中横向显示ListBox
  7. cocos2dx 3.x(场景(层)的生命周期)
  8. zipalign内存对齐优化
  9. P51、面试题5:从尾到头打印链表
  10. go与json
  11. 读取Word文档的标题
  12. 剑指offer之有序二维数组查找
  13. 13.C++-静态成员变量、静态成员函数
  14. 计算机网络之IP协议族
  15. anaconda 命令集合
  16. ARVE: Augmented Reality Applications in Vehicle to Edge Networks
  17. VUE—打印(原生态网页打印)
  18. Angular2入门:TypeScript的函数 - 剩余参数和箭头函数
  19. virtualBox下Centos系统扩展LVM磁盘空间
  20. chorem浏览器无法下载

热门文章

  1. 测试开发之网络篇-IP地址
  2. Windows 11,一个新功能,一场新屠杀
  3. GitHub Desktop的使用,创建项目、上传文件,设置忽略文件
  4. hdu 6048 Puzzle 拼图 逆序数
  5. Retrofit使用Kotlin协程发送请求
  6. 第二章 - Java与协程
  7. Centos中安装Node.Js
  8. 令牌桶限流思路分享(PHP+Redis实现机制)
  9. 深入理解Java多线程——线程池
  10. 一道内部ctf文件包含题