「Java架构学习交流」从基本概念深入到实现,跟面试官侃半小时MySQL事务隔离性

提到MySQL的事务 , 我相信对MySQL有了解的同学都能聊上几句 , 无论是面试求职 , 还是日常开发 , MySQL的事务都跟我们息息相关 。
而事务的ACID(即原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability)可以说涵盖了事务的全部知识点 , 所以 , 我们不仅要知道ACID是什么 , 还要了解ACID背后的实现 , 只有这样 , 无论在日常开发还是面试求职 , 都能无往而不利 。
为了大家更好的阅读体验 , 对ACID的深入分析将分为上下两篇 。
本篇为上篇 , 主要围绕ACID中的I,也就是“隔离性”展开 , 从基本概念 , 到隔离性的实现 , 最后以一个实战案例进行融会贯通 。
嗯 , 看完你都能理解 , 那跟面试官侃半小时隔离性就没问题了 。
1.事务隔离性的基本概念1.1什么是ACID中的Isolation,隔离性Isolation,隔离性 , 也有人称之为并发控制(concurrencycontrol) 。 事务的隔离性要求每个事务读写的对象对其他事务都是相互隔离的 , 也就是这个事务提交前 , 这个事务的修改内容对其他事务都是不可见的 。 事务的隔离性 , 主要是解决不同事物之间的相互读写影响 。
所谓的读写影响注意分为三种:
脏读:读到了别的事务尚未提交(commit)的变更 , 别人没提交 , 我读到了 。 不可重复读:别的事务提交了变更 , 被当前事务读到了 。 然后导致本事务多次select的结果不一样 , 读到了别的事务提交的内容 。 幻读:也是读到了别的事务提交的内容 , 但是跟上面的不同之处在于 , 读到了原本不存在的记录 。注意 , 不可重复读 , 主要是读到了别的事务update的内容 。 而幻读 , 是读到了别的事务insert的内容 。
1.2隔离性的隔离级别为了解决事务隔离性的问题 , 数据库一般会有不同的隔离级别来解决相应的读写影响 。
读未提交:一个事务B还没提交 , 它的修改就被别的事务A读到了 。 读已提交:一个事务B提交后 , 它的修改被其他事务A看到了 。 可重复读:一个事物B提交前和提交后 , 事务A都无法读到事务B的变更 。 串行化:对同一行记录 , 当出现不同事物的读写冲突时 , 是通过串行化的方式解决的 , 后一个事务必须等前一个事务完成才能执行 。不同隔离级别能够解决不同的隔离性问题 。
「Java架构学习交流」从基本概念深入到实现,跟面试官侃半小时MySQL事务隔离性
文章图片
需要注意的是 , 这是标准事务隔离级别的定义 。 在MySQL的innodb引擎中 , 在可重复读级别下 , 通过mvcc解决了幻读的问题 , 具体实现我们后面再讲 。
同时 , 需要注意的是 , 到目前为止 , 我们说的读 , 都是”快照读” , 普通的select 。 后面我们还会提到“当前读” , 是不一样的哦 。
2.事务隔离性的实现要实现事务的隔离性 , 需要了解两个方面的内容 , 一个是锁 , 一个是多版本并发控制(MVCC) 。
2.1事务的行锁InnoDB中 , 实现了两种标准的行级锁:
共享锁(SLock) , 也叫读锁 , 允许事务读取一行数据 。 排它锁(XLock) , 也叫写锁 , 允许事务删除或者更新一行数据(注意 , 这里没有提到插入哦 , 插入涉及到幻读 , 可以看文章最后的说明)普通select语句不会有任何锁 , 那么如何获得共享锁和排它锁呢?
Select…lockinsharemode语句能够获得共享锁Select…forupdate(特殊的select , 用mysql简单实现分布式锁经常用它)、Update、delete语句能够获得排它锁当一个事务A已经获得了行r的共享锁 , 那么另一个事务B可以立刻获得行r的共享锁 , 因为不会改变r的数值 , 这种叫做锁兼容 。
如果这时候有事务C希望获得行r的排它锁 , 那么就必须等待事务A和事务B释放行r的共享锁之后 , 才能获得排它锁 , 这种叫做锁不兼容 。
「Java架构学习交流」从基本概念深入到实现,跟面试官侃半小时MySQL事务隔离性