mysql的mvcc笔记

面试被问到mvcc,一脸懵逼,尴尬。查了查,记录下来;

事务特性ACID

原子性(Atomicity): 事务的操作不可分割,共同失败或成功。
隔离性(Isolation): 不同事物间相互不影响,称为隔离性,但是各个数据库实现时并不是直接完全隔离,事务执行的中间结果对其他事务是透明的,方便灵活使用
一致性(Consistency): 数据成功或者失败后和预设结果一致,即几个并行执行的事务,执行结果与按照串行执行结果一致。
**持久性(Durability):**事务成功后数据会持久化到磁盘,不会丢失。

隔离级别

事务的ACID的特性说了事务具有隔离性,而不同事务的隔离基本做法就是加锁。通过对锁的控制来实现事务的隔离性,其中Mysql默认的隔离级别是重复读(RR),而Oracle、Sql Server则是读已提交(RC);

读未提交: 可以读取其他事务未提交的数据,这个隔离性是最差的,一旦数据库的一条数据同时被多人操作就会出现问题
读已提交: 可以读取其他事务已经提交的数据,这个是Oracle的默认隔离级别
重复读: 不会读取到其他事务已经提交的数据(指当前事务已经读取到的数据),读到的数据都是本事务开始时的快照信息,被称为快照读。
**串行化:**所有事物完全隔离,互相不干扰,这也是最严格的隔离级别,注意串行化不同事物的读写也会阻塞。

参考 Mysql夺命50问-你的面试宝典_mysql explain 面试题-CSDN博客

事务问题分类:

脏读: 读到了其他事务未提交的数据

**不可重复读:**在一个事务操作中,读取到了其他事务提交的数据。

**幻读:**读到了其他事务新增的数据

隔离级别存在的问题

读未提交: 有脏读(读到了其他事务未提交的修改数据)、不可重复读(读到了其他事务已提交的修改数据)、幻读(读到了其他事务新增的数据)等全部问题,这个隔离级别啥问题都解决不了,所以没人用
读已提交: 解决脏读问题,但仍有不可重复读和幻读的问题
重复读: 解决脏读、不可重复读的问题,仍有幻读的问题
**串行化:**解决全部问题,就是效率太低

mvcc

什么是mvcc

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制,是一种并发控制的方法,;

解决问题:

  • 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能
  • 解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题

mvcc原理

主要依赖于数据记录中的三个隐藏字段、undolog,read view来实现的。

1、隐藏字段

每行记录,除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段:

  • DB_ROW_ID:6字节,隐藏的主键,如果数据表没有主键,那么innodb会自动生成一个6字节的row_id
  • DB_TRX_ID:6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id
  • DB_ROLL_PTR:7字节,回滚指针,用于配合undo日志,指向上一个旧版本

假设记录如图所示:

2. undo log(回滚日志)

undo log是InnoDB的行为,主要用途是用于事务回滚和MVCC使用,在事务开始之前数据就会记录数据到undolog buffer(Buffer Pool中也是数据页形式存在)中,记录的是数据修改前的数据;

3. read view(快照读)

Read View是事务进行快照读操作的时候生产的读视图,在该事务执行快照读的那一刻,系统会生成一个此刻的快照,记录并维护系统此刻活跃事务的id,用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当作条件去判断当前事务能够看到哪个版本的数据,有可能读取到的是最新的数据,也有可能读取到的是当前行记录的undolog中某个版本的数据

1)可见性算法

将要被修改的数据的最新记录中的DB_TRX_ID(当前事务id)取出来,与系统此刻其他活跃事务的id去对比,如果DB_TRX_ID跟Read View的属性做了比较,不符合可见性,那么就通过DB_ROLL_PTR回滚指针去取出undolog中的DB_TRX_ID做比较,即遍历链表中的DB_TRX_ID,直到找到满足条件的DB_TRX_ID,这个DB_TRX_ID所在的旧记录就是当前事务能看到的数据。

2)可见性规则

首先要知道Read View中的三个全局属性:

  • trx_list:一个数值列表,用来维护Read View生成时刻系统正活跃的事务ID(1,2,3)
  • up_limit_id:记录trx_list列表中事务ID最小的ID(1)
  • low_limit_id:Read View生成时,系统即将分配的下一个事务ID(4)

当前读

读取的是最新版本的记录,读取时还要保证其它并发事务不能修改当前记录,会对读取的记录进行加锁

  • 共享锁:select lock in share mode
  • 排它锁:select for update 、update、 insert 、delete

RR 和RC 的快照读有什么区别

RR (可重复读)隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View.

在RC(读已提交)隔离级别下,是每个快照读都会生成并获取最新的Read View;

其他记录

mysql的日志

三种日志的区别:undo log、redo log 、bin log

其他日志:relay log(中继日志) 、general query log(一般查询日志)、慢查询日志、error log(错误日志)

Buffer pool(缓冲池)

InnoDB设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能。

当读取数据时,如果数据存在于Buffer pool中,那么直接从Buffer pool中拿,否则从磁盘中拿。

修改数据时,如果数据存在于Buffer pool中,那么直接修改Buffer pool中数据所在的页,然后将其页设置为脏页,为了减少磁盘IO,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入磁盘。

redo log

断电丢失问题:Buffer pool是基于内存的,如果断电重启,还未来的及写入磁盘的脏页数据就会丢失。 问题如何解决/

解决问题方法:

为了防止断电丢失的问题,当有一条记录需要更新时,InnoDB引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以redo log的形式记录下来,这个时候,更新就算完成。后续由后台线程选择一个合适的时机将脏页写入磁盘。

这就是:WAL(Write-Ahead Logging)技术:MySQL的写操作并不是立刻写在磁盘上,而是先写日志,然后在合适的时间再写入磁盘。

binlog 归档日志

undo log 和 redo log 是由InnoDB存储引擎 产生的

binlog 是由Server层 产生的,记录全部库表和数据的修改记录(不记录查询操作)

binlog有三种格式类型

STATEMENT(默认格式):记录SQL语句,但是存在动态函数的问题,比如获取当期时间、uuid
ROW:记录行数据最终被修改成什么样了。如果批量执行update语句,那可能会导致binlog文件过大。
MIXED:包含了上述两种模式,根据不同情况自动使用ROW和STATEMENT

bin log和redo log的区别:

  • 层次不同:redo log 是InnoDB存储引擎实现的,bin log 是MySQL的服务器层实现的,但MySQL数据库中的任何存储引擎对于数据库的更改都会产生bin log。

  • 作用不同:redo log 用于碰撞恢复(crash recovery ),保证MySQL宕机也不会影响持久性;bin log 用于时间点恢复(point-in-time recovery),保证服务器可以基于时间点恢复数据和主从复制。

  • 内容不同:redo log 是物理日志,内容基于磁盘的页**Page** ;bin log的内容是二进制,可以根据**binlog_format**参数自行设置。

  • 写入方式不同:redo log 采用循环写的方式记录;binlog 通过追加的方式记录,当文件大小大于给定值后,后续的日志会记录到新的文件上。

  • 刷盘时机不同:bin log在事务提交时写入;redo log 在事务开始时即开始写入。

参考文章

​​​​​​一篇了解全MVCC - 程序员Forlan - 博客园

MySQL数据库七种日志介绍_mysql日志-CSDN博客

MySQL(日志)_mysql日志-CSDN博客

相关推荐
大霸王龙12 分钟前
在 Django 中使用 SMTP 发送邮件是一个常见的需求
数据库·django·sqlite
iVictor15 分钟前
MySQL 优化利器 SHOW PROFILE 的实现原理
mysql
小王爱吃月亮糖36 分钟前
C++进阶-1-单继承、多继承、虚继承
开发语言·c++·笔记·学习·visual studio
纪伊路上盛名在1 小时前
爬虫1:uniprot蛋白质序列数据+canvas图片
数据库·学习·知识图谱·学习方法
小王爱吃月亮糖1 小时前
补充--C++的项目结构和管理
数据结构·c++·笔记·学习
程序员黄同学3 小时前
如何使用 Python 连接 MySQL 数据库?
数据库·python·mysql
新手小袁_J4 小时前
实现Python将csv数据导入到Neo4j
数据库·python·neo4j·《我是刑警》·python连接neo4j·python导入csv·csv数据集导入neo4j
シ風箏4 小时前
Neo4j【环境部署 02】图形数据库Neo4j在Linux系统ARM架构下的安装使用
linux·数据库·arm·neo4j
张声录14 小时前
【ETCD】【实操篇(四)】etcd常见问题快问快答FAQ
数据库·etcd
CherishTaoTao6 小时前
sqlite基础
数据库·oracle·sqlite