正如标题,MVCC到底是什么?
MVCC:多版本并发控制。把数据库的行锁与行的多个版本结合起来,实现并发控制。
作用:
1.Innodb的MVCC能防止幻读的发生。(不是每个MVCC都可以,看MVCC怎么实现)
2.实现了多个事务并发下,读操作的非阻塞。
场景:MVCC只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据。行,而SERIALIZABLE会对所有读取到的行都加锁。
原理:MVCC保存了某一时刻数据的一个快照。意思就是无论事物运行了多久,它们都能看到一致的数据。也就是说在相同的时间下,不同的事物看相同表的数据是不同的。
底层原理:通过在每行记录后面保存两个隐藏的列来实现。这两个列,一个保存了行的创建时间,一个保存了行的过期时间(删除时间)。并且存储的并不是真实的时间值,而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动递增。开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。
事务操作:
SELECT
InnoDB会根据以下两个条件检查没行记录:
a. InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本小于或等于事务的系统版本号),这样可以确保事务读取到的行,要么是事务开始前已经存在的,要么是事务自身插入或者修改过的。
b. 行的删除版本要么未定义,要么大于当前事务的版本号。这样可以确保事务读取到的行,在事务之前未被删除。只有符合上述两个条件的记录,才能被作为返回查询结果.
INSERT
InnoDB为新插入的一行保存当前系统版本号作为行版本号
DELETE
InnoDB为删除的每一行保存当前系统版本号作为删除标识,如果事务a版本号为3且之后执行了删除事务b的版本号为5,那么即使删除了数据,在事务a中还是能查出数据。
UPDATE
UPDATE为插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识。
锁:
MySQL InnoDB支持三种行锁定方式:
行锁(Record Lock):锁直接加在索引记录上面,锁住的是key。
间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙不变。相当于在行间隙的上或下加锁。这样就不能随便加锁。
Next-Key Lock :行锁和间隙锁组合起来就叫Next-Key Lock
默认情况下,InnoDB工作在可重复读隔离级别下,并且会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。
扩展锁的知识:
X :写锁:又称排他锁、X锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
S:读锁:也叫共享锁、S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
IX::意向排他锁:表示有加排他锁的意向。
IS::意向共享锁:表示有加共享锁的意向。
顺便提下日志
binlog:
MySQL是多存储引擎的,不管使用那种存储引擎,都会有binlog,而不一定有redo log,简单的说,binlog是MySQL Server层的,redo log是InnoDB层的。
binlog:用于记录用户对数据库更新的SQL语句信息,例如更改数据库表和更改内容的SQL语句都会记录到binlog里,但是对库表等内容的查询不会记录
redo和undo:
redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。
1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
MVCC就是利用undo实现的,当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
总结:1.无非就是通过两个标志位记录版本号,来实现多事务操作下,读的非阻塞(即不会因为同一时刻受到其他事物的增删改的影响,利用undo日志查看到版本号)。2.通过 Next-Key Lock 实现防止幻读的发生。