事务的实现

原子性 A

持久性 D

隔离性

事务的四种隔离级别

  • 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到
  • 读已提交:一个事务提交之后,它做的变更才会被其他事务看到
  • 可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。在可重复读隔离级别下,未提交变更对其他事务也是不可见的
  • 串行化:对于同一行记录,“写”会加”写锁”,“读”会加”读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行

事务的四种隔离级别解决什么问题

  • 读未提交 — 无
  • 读已提交 — 解决脏读
  • 可重复读 — 解决不可重复读,部分幻读
  • 串行化 — 解决幻读

什么是脏读、幻读、不可重复读

  • 脏读:读到了别人还没提交的数据(对方回滚后,你读到的是”脏”的)
  • 不可重复读:同一事务里,两次读同一行,结果不一样(别人中间提交了更新)
  • 幻读:同一事务里,两次按条件查询,第二次多/少了几行(别人中间插入/删除了满足条件的行)

四种隔离级别实现原理

  • 可重复读:执行事务前创建一个视图,访问的时候以视图的逻辑结果为主,整个事务期间都会使用这个视图
  • 读已提交:视图在 SQL 执行前开始创建
  • 读未提交:直接返回记录的最新值
  • 串行化:对于记录进行加锁

为什么可重复读不能解决幻读的问题,如何解决

快照读

  • 普通 select 语句,通过 MVCC 方式解决了幻读

当前读

  • select for update 语句,此类语句会跳过视图,直接读记录
  • 解决方案:需要通过间隙锁和 Next-Key Lock 解决,这是 InnoDB 在可重复读的级别下额外引入的机制
    • 间隙锁 — 锁住一个范围内的”空隙”,阻止其他事务在这个范围内插入新行
    • Next-Key Lock — 行锁 + 间隙锁,锁住行本身及其前面的间隙
  • 为什么单纯的间隙锁无法解决幻读?
    • 间隙锁锁的是开区间的记录,不包含端点(记录本身)
    • 间隙锁之间不互斥,两个事务可以同时持有同一个间隙的间隙锁
    • 间隙锁的设计目标是”阻止插入”,而不是”互斥访问”
    • 间隙锁可以解决:防止插入新行
    • 不能解决:防止修改已有行,单独解决幻读

一致性 C

关联