MySQL数据库Innodb如何在RR级别下解决幻读?

  • 表象:快照读(非阻塞读) – 伪MVCC
  • 内在:next-key锁(行锁 + gap锁 [间隙锁] )

Innodb在可重复读隔离级别下,基于伪MVCC机制实现的快照读(即非阻塞读)来避免让我们看到幻行。
读取数据时的非阻塞就是MVCC机制,MVCC代表着多版本并发控制,读不加锁,读写不冲突,极大地增大了系统的并发性能。

当前读和快照读
  1. 当前读:上了锁的 增删改查语句,操作数据的最新状态
  2. 快照读:不加锁的非阻塞读(有可能查询到数据的以前版本) – select
RC、RR级别下的Innodb的非阻塞读如何实现?(读不加锁,读写不冲突如何实现?)
  1. 数据行里的DB_TRX_ID、DB_ROLL_PRT、DB_ROW_ID字段

DB_TRX_ID : 跟事务相关的,用来标识最近一次对本行记录做修改的id(即事务id)
DB_ROLL_PRT:回滚指针,写入日志的信息(在日志中记录这修改之前的数据方便回滚)
DB_ROW_ID:行号

2.undo日志

undoLog日志分为两种。
一种是insertUndoLog,此日志表示事务对insert新记录产成时需要的日志记录,主要是发生回滚时需要,事务添加成功提交后即可丢弃。
另一种是updateUndoLog,事务对数据delete或者update时所产生的undolog,不仅在回滚时需要,快照读时也需要,所以不能随便删除。只有当数据库中的快照读不涉及该日志记录,该回滚记录才会被线程删除。

通过日志实现了数据的多个版本,每个版本之间都通过DB_ROLL_PRT进行连接。

3.read view

主要是用来进行可见性判断的,判断最终查询到哪个版本的数据。事务的id都是递增的,通过事务得id去undolog中找到该事务适应的数据版本(可见性算法实现)

RR级别下如何避免幻读?

快照读并不是避免幻读现象的根本。真正防止幻读的是next-key锁

  • 行锁:是对单个行记录上的锁
  • Gap锁:锁定一个范围,但不包括记录本身,防止同一事务的两次当前读出现幻读。

如果精确查询,条件全部命中,则不会使用Gap锁,只会加记录锁
范围查询以及where条件部分命中或者全部不命中时,则会加Gap锁。

  • Gap锁实质上是防止插入的,如果表中有3,5,7 , 9这么几条数据。如果在进行delete操作id为7的数据时,那么Gap锁就会给(5,7] 和(7,9]这个区间进行上锁,防止数据的插入。

Gap锁会用在唯一索引或者主键的当前读中
Gap锁也会用在非唯一索引或者不走索引的当前读中

  • 如果不走索引Gap锁会锁住整个表 此时Gap锁比表锁更消耗性能,应避免。

你可能感兴趣的:(MySQL数据库Innodb如何在RR级别下解决幻读?)