Mysql-MVCC
mysql默认隔离级别为Repeatable Read可重复读
-
当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select ... in lock share mode(共享锁),
select ... for update , select ... for update / insert / delete (排他锁)都是一种当前读
-
快照读
简单的select(不加锁,非阻塞读)就是快照读,读取的是记录的可见版本,有可能是历史数据(一个快照读伴随着一个ReadView)
-
Read Committed : 每次select,都生成一个快照读
-
Repeatable Read : 开启事务后,只有第一个select语言会生成快照读,之后的select都会复用快照
-
Serializable : 快照读会退化为当前读
-
-
MVCC
Multi-Version Concurrency Control 多版本并发控制
维护一个数据的多个版本,使得读写操作没有冲突。快照读为MVCC提供了一个非阻塞读的功能。MVCC的具体实现,依赖于数据库记录的三个隐藏字段、undo log日志、ReadView。
而给MVCC加上锁,就保证了事务的隔离性
而一致性(事务执行前后,保证数据是一致的),而一致性事由redo log 和 undo log共同来保证的
-
三个隐藏字段
DB_TRX_ID : 事务ID,记录插入这条记录或最后一次修改记录的事务ID(自增)
DR_ROLL_PTR : 回滚指针,指向这条记录的上一个版本,用于配合undo log
DB_ROW_ID :隐藏主键,如果表结果没有指定主键,则会生成,否则不会
-
undo log 日志
回滚日志,在insert、update、delete的时候产生,便于数据回滚
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除
而update,delete的时候,产生的undo log日志,需要在回滚和快照读中用到,不会被立即删除
-
undo log 版本链
不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的记录,链表的尾部是最开始的历史记录
-
ReadView 读视图
快照读,读取的是当前可见记录(可能会有多个历史记录),那么到底读取那条记录,就是由ReadView来决定的,ReadView记录并维护系统当前活跃的事务ID(未提交)
ReadView有四个核心字段:
-
m_ids : 当前活跃的事务ID集合
-
-
max_trx_id : 预分配事务ID,当前最大事务ID+1
-
creator_trx_id : ReadView创建者的事务ID
实现原理:trx_id,当前undo log记录对应的当前事务ID,在决定获取那个历史版本数据时,就是拿trx_id和ReadView中的四个字段属性进行比对,取出匹配成功的记录
-
事务原理:
事务是一组操作集合,是一个不可分割的工作单位,事务会把所有操作作为一个整体一起提交或撤销,即:要么同时成功,要么同时失败
事务的四大特性:ACID
事务的原子性、一致性和持久性,是由innodb存储引擎底层的两份日志来保障的(undo log和redo log)
事务的隔离性,是由innodb存储引擎底层的锁机制和MVCC来实现的
redo log 重做日志
记录的是事务提交是数据页的物理修改,用来实现事务的持久性
该日志文件由两部分组成:重做日志缓冲(redo log buffer,存在内存中)和 重做日志文件(redo log file,存在磁盘中)。当事务提交之后,会把所有修改信息都存在该日志文件中,用于在刷新脏页数据到磁盘发生错误,用于数据的恢复使用。
undo log 回滚日志
主要用来解决事务的原子性
用于记录数据被修改前的信息,作用包含两个:回滚日志 和 MVCC(多版本并发控制)
undo log 记录的是逻辑日志,而 redo log记录的是物理日志。当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,他记录一条对应的反向update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
undo log销毁:undo log在事务执行时产生,事务提交时,并不会立即删除,因为这些日志可能还用于MVCC
undo log存储:采用段的方式进行管理和记录,存放在rollback segment回滚段中,内部还有1024个undo log segment
全局锁:数据库备份时会加全局锁
元数据锁:对表结构的锁定。当有活跃的事务正在对表数据进行操作时,不允许对表结构进行修改
意向锁:解决行锁和表锁的冲突。当要加表锁时,会去扫描每行记录是否加有行锁,开销大,这个时候就有了意向锁(共享锁和排他锁),当加行锁时会自动加意向锁,当再加表锁时,表锁去查是否有意向锁就可以,则不需要遍历每行去处理了。
Mysql存储结构:
Buffer Pool:
Change Buffer:
mysql 5.x版本的时候是 插入缓冲区 insert buffer
mysql 8.0 开始,插入缓冲区 更换为 change buffer 更改缓冲区(针对二级索引)
Adaptive Hash Index 自适应hash:
Log Buffer 日志缓冲区:
System Tablespace && File-Per-Table Spaces
通用表空间 & Undo Tablespaces & 临时表空间
DoubleWrite Buffer File 双写缓冲区 & Redo Log 重做日志
后台线程的作用:在合适的时间将Buffer pool中的数据刷新到磁盘中