借鉴:
https://blog.csdn.net/Huangjiazhen711/article/details/127900821
https://blog.csdn.net/qq_42757463/article/details/132618759
https://blog.csdn.net/weixin_62458944/article/details/132721814
https://blog.csdn.net/m0_73311735/article/details/127935751
1.保证事务的原子性:
每当我们要对一条记录做改动时(这里的改动可以指INSERT、DELETE、UPDATE),把回滚时所需的东西记下来。比如:
(1)你插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删
掉就好了
(2)你删除了一条记录,至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入
到表中就好了
(3)你修改了一条记录,至少要把修改这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值
MySQL处于性能考虑,数据会优先从磁盘加载到Buffer Pool中,在更新Buffer Pool中数据之前,会优先将数据记录到undo log中。记录undo log日志,MySQL不会直接去往磁盘中的xx.ibdata文件写数据,而是会写在undo_log_buffer缓冲区中,因为工作线程直接去写磁盘太影响效率了,写进缓冲区后会由后台线程去刷写磁盘。
2.分两种格式的undo log:
(1)insert undo log格式:记录的是insert 语句对应的undo log
(2)update undo log格式:
1.作用:mysql服务崩溃后,事务恢复。保证了事务的持久性。
update包含两步操作,先查询到对应的行记录,再根据条件进行更新操作。如果没有redo log的话,MySQL每次的update操作都要更新磁盘文件,整个过程的I/O成本和查询成本都很高。更新数据优先存在缓存中,事务提交之后再刷redo log 持久化到磁盘
图中的步骤:
(1):从磁盘加载数据到内存
(2):在内存中修改数据
(3):把新数据写到Redo Log Buffer中
(4):把Redo Log Buffer中数据持久化到Redo Log文件中
(5):把Redo Log文件中数据持久化到数据库磁盘中
2.为什么需要写Redo Log Buffer和Redo Log FIle?直接将持久化到磁盘不好吗?
直接写磁盘会有产生严重的性能问题:
(1):InnoDB在磁盘中存储的基本单元是页,可能本次修改只变更一页中几个字节,但是需要刷新整页的数据,就很浪费资源。
(2):一个事务可能修改了多页中的数据,页之间又是不连续的,就会产生随机IO,性能更差。
这种方案叫做WAL(Write-Ahead Logging),预写日志,就是先写日志,再写磁盘。写入redo log的方式使用了追加操作,所以操作顺序是顺序写。
3.redo log什么时候刷到磁盘
(1):MySQL正常关闭时。
(2):当redo log buffer中记录写入量大于其内存空间的一半的时候,会触发落盘。
(3):InnoDB的后台线程每隔1s,将redo log buffer持久化到磁盘。
(4):每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘。
1.作用:
(1)数据恢复,如果MySQL数据库意外挂了,可以利用bin log进行数据恢复,因为该日志记录所有数据库所有的变更,保证数据的安全性。
(2)数据复制,利用一定的机制将主节点MySQL的日志数据传递给从节点,实现数据的一致性,实现架构的高可用和高性能。
2.日志内容:
(1)查看bin log位置:通过命令show variables like ‘%log_bin%’;查看bin log最终输出的位置。
log_bin_basename: 是bin log日志的基本文件名,后面会追加标识来表示每一个文件
log_bin_index: 是binlog文件的索引文件,这个文件管理了所有的binlog文件的目录
(2)通过 SHOW BINARY LOGS;查看当前的二进制日志文件列表及大小,如下图:
(3)修改 bin log位置:修改MySQL的my.cfg或my.ini配置
#启用二进制日志
log-bin=cxw-bin
binlog_expire_logs_seconds=600
max_binlog_size=100M
复制代码
log-bin: bin log日志保存的位置
binlog_expire_logs_seconds: bin log日志保存的时间,单位是秒
max_binlog_size: 单个bin log日志的容量
(4)查看日志内容:show binlog events命令工具查看bin log日志
show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];
复制代码
IN ‘log_name’ :指定要查询的binlog文件名(不指定就是第一个binlog文件)
FROM pos :指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算)
LIMIT [offset] :偏移量(不指定就是0)
row_count :查询总条数(不指定就是所有行)
(5)bin log格式:默认是ROW类型
Statement格式:每一条会修改数据的sql都会记录在bin log中
优点:不需要记录每一行的变化,减少了bin log日志量,节约了IO,提高性能。
缺点:比如sql中存在函数如now()等,依赖环境的函数,会导致主从同步、恢复数据不一致
ROW格式:为了解决Statement缺点,记录具体哪一个分区中的、哪一个页中的、哪一行数据被修改了
优点:清楚的记录下每一行数据修改的细节,不会出现某些特定情况下 的存储过程,或function无法被正确复制的问题。
缺点:比如对ID<600的所有数据进行了修改操作,那么意味着很多数据发生变化,最终导致同步的log很多,那么磁盘IO、网络带宽开销会很高。
Mixed格式: 混合模式,即Statment、Row的结合版
对于可以复制的SQL采用Statment模式记录,对于无法复制的SQL采用Row记录
事务提交后,redo log和binlog都要持久化到磁盘,但这两个是独立的逻辑,可能出现版成功的状态,这样就造成两份日志之间的逻辑不一致:
(1)如果在redo log刷入磁盘之后,MySQL突然宕机了,而binlog还没有来得及写入。
(2)如果在将binlog刷入磁盘之后,MySQL突然宕机了,而redo log还没来得及写入。也会导致主从不一致。
1.两阶段提交作用: 保证了两个日志文件的数据一致性
2.两阶段提交的缺点是性能更差:磁盘I/O次数高