# MVCC
多并发版本控制
- 当前读:`select lock in share mode,select for update, update, insert, delete都是一种当前读,它读取的是最新的数据,并且在读取时保证其它事务不会修改当前记录
- 快照读:不加锁的非阻塞读;前提是隔离级别不是串行级别;
实现:
隐式字段:表记录DB_ROW_ID,DB_TRX_ID当前操作此记录的事务ID;DB_ROLL_PTR回滚指针,用于配合undo日志,指向上一个版本;delete_flag
undo log:不同事务或相同事务对同一记录的修改,会导致此记录的undo log成为一记录版本线性表,链首是最新的旧记录,链尾是最早的旧记录
- Insert Undo Log
- Update Undo Log
- Delete Undo Log:purge线程清理DELETED_BIT=true的记录,它维护一个rearview,如果对purege可见,则可安全删除
Read View:已提交读与可重复读区别在于ReadView生成的策略不同,InnoDB为每个事务构造了一个数组,记录并维护系统当前活跃事务的ID 有个当前活跃着的读写事务的列表,也就是begin了还未提交的事务列表。通过这个列表判断某个版本对当前事务是否可见;事务开启时会分配一个ID,这个ID递增的,最新的事务ID值越大
Creator_trx_id 创建它的事务ID。
只有对表记录有改动(Insert、Delete、Update)时才会为事务分配事务ID,只读事务中的ID值默认为0trx_ids 生成RV时当前系统活跃的读写事务的事务ID列表 Up_limit_id 活跃事务中最小的事务ID Low_limit_id 生成RV时系统应该分配给下一个事务的ID值,系统最大事务ID值,区别于正在活跃的事务ID
设计思路:
- ReadUncommited:可读到未提交事务修改过的记录,所以直接读取记录的最新版本
- Serializable:使用加锁的方式访问数据
- ReadCommitted,RepeatableRead:保证读到已经提交了的事务修改过的记录
- 可见性算法:修改数据的最新记录中的DB_TRX_ID当前事务ID,与系统当前其它活跃事务ID对比,如果不符合可见性,则顺着DB_ROLL_PTR回滚指针取出Undo Log中的DB_TRX_ID比较,直到找到符合条件的DB_TRX_ID,这个记录就是能看见的最老的版本
ReadCommitted 快照读:事务中每次快照读都生成一个快照和ReadView
RepeatableRead快照读:事务中对某记录的第一次快照读创建一个快照和ReadView,此后调用快照读时调用的是同一个ReadView
# MySql锁类型
- 共享锁S和排它锁X
- 读锁是共享锁,通过lock in share mode 实现
- 写锁是排它锁,会阻塞写锁和读锁,分为行锁和表锁
- 表锁和行锁
- 表锁会锁定整张表并阻塞其它用户对表的读写操作
- 行锁分乐观锁和悲观锁,悲观锁通过for update实现,乐观锁通过版本号实现
# 两个维度
- 共享锁:读锁(s锁),多个事务对同一数据共享访问,不能操作修改
- 排他锁(行锁):写锁(X锁)互斥锁,独占锁,事务获得X锁,其它事务就不能获取它的读和写锁,只有获取到排他锁的事务可以进行读取和修改
- 意向锁(IS)
- 意向共享锁(表锁)
- 意向排他锁(表锁)
# SQL执行过程
除从磁盘加载文件和将操作前的数据保存到undo日志中,其它的操作都是在内在中进行的
# Buffer Pool:
更新操作实际在Buffer Pool中执行
# Undo日志文件:
记录修改前的数据
# Redo日志文件:
记录修改后的数据
# Binlog日志文件
逻辑日志,模式:Statement,Row,Mixed
- BufferPool中没有数据则从磁盘加载缓存数据到Buffer Pool
- 记录更新前的记录数据到Undo Log,便于回滚操作
- 更新内存中的数据Buffer Pool
- 写Redo日志到Redo Log Buffer
- Redo Log Buffer中的日志刷入磁盘(Os Cache)
- 准备提交事务,将binlog文件写入到磁盘
- 写入binlog文件与位置,写入commit标记
- IO线程刷新BufferPool中的脏数据到磁盘文件