千人千面MVCC

每个事务可以读到特定版本的数据,就是MVCC
由于undo log的存在,可以从最新版本推算之前版本
image.png
undo log的作用

  • 回滚事务roll back
  • 获得行记录的历史版本

    快照读(一致性非锁定读)

    普通的select就是快照读

  • 不锁定数据的情况下,读取数据的特定历史版本

  • 版本由事务的具体需求确定:
    • 读已提交:根据每次SELECT时,其他事务的提交情况

比如trx_id=230修改了name= “d”,但是还没有提交事务,虽然事务已经把数据的内容修改掉了,但是其他事务去读取这一行数据的时候,是不能把这一行给读取出来的,这是读已提交的时候,我现在select的时候,发现未提交怎么办,那就用undo还原成未修改的状态。也就是说读取的是190这个事务的提交的数据,这个数据一定是提交了,因为只有190提交了,230才能修改。所以我select的时候,展示的是name=’c’这条数据 。但是,如果trx_id=230提交了,那么select的时候展示的就是name=’d’这条数据了。

  • 可持续读:根据事务开始时,其他事务的提交情况

比如说,事务a在158之后这个时刻,它begin了,有两个事务更改了字段并提交了,那么它select name这个字段的时候,只能拿到name=’b’这个版本的事务,这叫可持续读。怎么展示之前版本,就用undo log。
image.png

当前读(一致性锁定读)

image.png

  • 读取数据的当前版本,并加锁
  • 若当前版本已经被加锁且不兼容,则阻塞等待
  • X锁:UPDATE、DELETE、SELECT FOR UPDATE 写互斥锁 不允许别人读写
  • S锁:SELECT IN SHARE MODE 读共享锁 不允许别人写

SERIALIZABLE是当前读

隔离问题

  • 脏读:读到了其他事务未提交的数据
  • 不可重复读:同样的查询读到的数据内容不一样
  • 幻读:同样的查询读到了更多的数据

image.png

如何解决幻读问题

  • MySQL在可重复读级别时,通过Next-Key锁解决了幻读问题
  • Next-key锁是行锁+间隙锁

image.png
image.png

  • 间隙锁的功能与行锁相同,只是针对间隙加锁
  • 间隙锁不分读写,也可以认为是读锁,不允许在间隙插入
  • 可重复读加锁时,将同时锁住数据及其左右间隙

    总结

  • InnoDB使用undo log实现了行记录历史查询

  • 快照读不需要加行锁,属于乐观锁的一种思路
  • 当前锁需要加行锁,为了并发控制
  • Next-key解决幻读问题