MySQL由几块组成
- 连接器
- 分析器
- 优化器
- 执行器
MySQL的三大log
blog
作用:
用于主从同步与数据恢复
记录内容:
已经完成的 DML(数据操作语句),主要是用于数据备份
redolog<重试日志>
作用:
- 崩溃恢复,用于事务的持久化,确保数据一致性
- 减少写磁盘IO慢的问题
记录内容:
记录数据页的物理变化(可以理解为记录的是DML造成的数据diff)
工作机制
MySQL写操作同步写的是缓存区与redolog,异步写的磁盘
思考:写redolog也是磁盘操作为啥比直接写数据快?
redolog是连续内存,顺序写入,不需要IO寻址,所以更快
工作机制
- 写入顺序:redolog 是顺序写入的,这是非常高效的。
- 两段式提交:在事务提交时,MySQL 首先将修改记录到 redolog,然后再修改数据页。这样,在系统崩溃时,系统可以通过 redolog 恢复事务的修改。
- 双写缓冲:为了防止单点故障导致的数据丢失,InnoDB 使用双写缓冲机制将数据同时写入 redolog 和缓冲池。
undolog
作用:
- 事务的回滚
- 多版本控制<MVCC由undolog实现>
记录内容:
旧值,用于事务的回滚
MVCC
多版本并发控制
可以看下面这个文章:
MVCC详解
MVCC与undolog如何实现版本链
mysql列中会存有俩隐藏字段:
- trx_id: 最近操作的事务id(自增)<事务可能未提交>
- roll_pointer: 最新undolog日志
单条数据的undolog内容:(链表结构) - data:mysql数据快照
- roll_pointer:这条数据上个的undolog地址
insert 语句产生的undolog roll_pointer内容为空,因为他没有上个版本
所以可以通过mysql数据+undolog 找到数据的历史版本
MVCC如何解决幻读问题
参考资料
简单概括如下:
开启事务的时候会产生一个视图,存本次事务id,所有活跃的事务id等
数据的事务id<最小的活跃事务id 证明已提交,可读
数据的事务id>本次事务id 证明未提交,不可读
数据的事务id属于活跃的事务id 证明当时未提交,不可读
这样就通过比较事务id的方式解决幻读了
MVCC如何实现读已提交与可重复读
读已提交实现原理
-
一致性读:
- 每次 SELECT 查询都会获取最新提交的快照。
- 事务读取时,会忽略未提交的事务所做的修改,读取其他事务已提交的最新版本。
事务ID比较:
-
读取时,检查数据行的创建版本号和删除版本号。
- 只读取创建版本号小于等于当前事务ID的数据,并且删除版本号大于当前事务ID的数据或删除版本号为空的数据。
可重复读实现原理
固定的快照视图
事务开始时,获取一个一致性快照,整个事务期间读取的数据视图保持不变
- 一致性读:
- 事务开始时,获取一个一致性快照。
- 在事务期间,所有 SELECT 查询基于该一致性快照。
-
事务ID比较:
- 读取时,检查数据行的创建版本号和删除版本号。
- 只读取创建版本号小于等于当前事务开始时的快照数据,并且删除版本号大于当前事务开始时的快照数据或删除版本号为空的数据。
区别:
- 可重复读在事务开始时,会生成一个一致性快照存当时活跃的事务id
- 读已提交比较的是数据上的事务id,可重复读比较多是快照数据上的事务id
扩展
interpolateparams 参数做了什么
https://wklken.me/posts/2021/01/22/golang-sql-driver-interpolateparams.html
interpolateparams=false
prepared -> execute -> close
好处:
- 避免通过引号组装拼接sql语句。避免sql注入带来的安全风险
- 可以多次执行的sql语句
interpolateparams=true
execute -> close
- 减少了prepared网络请求
- 会防止SQL注入, 在驱动中通过转义特殊字符实现的