事务的实现
原子性 A
持久性 D
隔离性
事务的四种隔离级别
- 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到
- 读已提交:一个事务提交之后,它做的变更才会被其他事务看到
- 可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。在可重复读隔离级别下,未提交变更对其他事务也是不可见的
- 串行化:对于同一行记录,“写”会加”写锁”,“读”会加”读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
事务的四种隔离级别解决什么问题
- 读未提交 — 无
- 读已提交 — 解决脏读
- 可重复读 — 解决不可重复读,部分幻读
- 串行化 — 解决幻读
什么是脏读、幻读、不可重复读
- 脏读:读到了别人还没提交的数据(对方回滚后,你读到的是”脏”的)
- 不可重复读:同一事务里,两次读同一行,结果不一样(别人中间提交了更新)
- 幻读:同一事务里,两次按条件查询,第二次多/少了几行(别人中间插入/删除了满足条件的行)
四种隔离级别实现原理
- 可重复读:执行事务前创建一个视图,访问的时候以视图的逻辑结果为主,整个事务期间都会使用这个视图
- 读已提交:视图在 SQL 执行前开始创建
- 读未提交:直接返回记录的最新值
- 串行化:对于记录进行加锁
为什么可重复读不能解决幻读的问题,如何解决
快照读
- 普通 select 语句,通过 MVCC 方式解决了幻读
当前读
- select for update 语句,此类语句会跳过视图,直接读记录
- 解决方案:需要通过间隙锁和 Next-Key Lock 解决,这是 InnoDB 在可重复读的级别下额外引入的机制
- 间隙锁 — 锁住一个范围内的”空隙”,阻止其他事务在这个范围内插入新行
- Next-Key Lock — 行锁 + 间隙锁,锁住行本身及其前面的间隙
- 为什么单纯的间隙锁无法解决幻读?
- 间隙锁锁的是开区间的记录,不包含端点(记录本身)
- 间隙锁之间不互斥,两个事务可以同时持有同一个间隙的间隙锁
- 间隙锁的设计目标是”阻止插入”,而不是”互斥访问”
- 间隙锁可以解决:防止插入新行
- 不能解决:防止修改已有行,单独解决幻读