我们举个栗子:假如更新 ID=1 记录的 name 字段,name 原始数据为小富,现改 name 为程序员内点事。
事务执行 update X set name = 程序员内点事 where id =1 语句时,先会在 undo log 中记录一条相反逻辑的 update X set name = 小富 where id =1 记录,这样当某些原因导致服务异常事务失败,就可以借助 undo log 将数据回滚到事务执行前的状态,保证事务的完整性。
未完全提交的事务,即事务已经执行 commit,但该事务内修改的脏页中只有一部分数据被刷盘,另外一部分还在 buffer pool 缓存上,如果此时数据库实例宕机重启,就需要用前滚来完成未完全提交的事务。将先前那部分由于宕机在内存上的未来得及刷盘数据,从 redo log 中恢复出来并刷入磁盘。
数据库实例恢复时,先做前滚,后做回滚。
如果你仔细看过了上面 MySQL 数据更新流程图就会发现,undo log、redo log、bin log 三种日志都是在刷脏页之前就已经刷到磁盘了,相互协作最大限度保证了用户提交的数据不丢失。
bin log(归档日志)
bin log 是一种数据库 Server层(和引擎类型无关),以二进制形式存储在磁盘中的逻辑日志。bin log 记录了数据库所有 DDL 和 DML 操作(不包含 SELECT 和 SHOW 等命令,因为这类操作对数据本身并没有修改)。
默认情况下,二进制日志功能是关闭的。可以通过以下命令查看二进制日志是否开启:
mysql> SHOW VARIABLES LIKE 'log_bin';+---------------+-------+| Variable_name | Value |+---------------+-------+| log_bin | OFF |+---------------+-------+
bin log 也被叫做归档日志,因为它不会像 redo log 那样循环写擦除之前的记录,而是会一直记录日志。一个 bin log 日志文件默认最大容量 1G(也可以通过 max_binlog_size 参数修改),单个日志超过最大值,则会新创建一个文件继续写。
bin log 日志的内容格式其实就是执行 SQL 命令的反向逻辑,这点和 undo log 有点类似。一般来说开启 bin log 都会给日志文件设置过期时间(expire_logs_days参 数,默认永久保存),要不然日志的体量会非常庞大。
mysql> show variables like 'expire_logs_days';+------------------+-------+| Variable_name | Value |+------------------+-------+| expire_logs_days | 0 |+------------------+-------+1 row in set mysql> SET GLOBAL expire_logs_days=30;Query OK, 0 rows affected
bin log 主要应用于 MySQL 主从模式(master-slave)中,主从节点间的数据同步;以及基于时间点的数据还原。
主从同步
通过下面的 MySQL 的主从复制过程图,来了解下 bin log 在主从模式下的应用。
用户在主库 master 执行 DDL 和 DML 操作,修改记录顺序写入 bin log;
从库 slave 的 I/O 线程连接上 master,并请求读取指定位置 position 的日志内容;
master 收到从库 slave 请求后,将指定位置 position 之后的日志内容,和主库 bin log 文件的名称以及在日志中的位置推送给从库;
slave 的 I/O 线程接收到数据后,将接收到的日志内容依次写入到 relay log 文件最末端,并将读取到的主库 bin log 文件名和位置 position 记录到 master-info 文件中,以便在下一次读取用;
mysql> SHOW VARIABLES LIKE 'slow_query%';+---------------------+--------------------------------------------------------+| Variable_name | Value |+---------------------+--------------------------------------------------------+| slow_query_log | OFF || slow_query_log_file | /usr/local/mysql/data/iZ2zebfzaequ90bdlz820sZ-slow.log |+---------------------+--------------------------------------------------------+
mysql> SHOW VARIABLES LIKE 'long_query_time';+-----------------+-----------+| Variable_name | Value |+-----------------+-----------+| long_query_time | 10.000000 |+-----------------+-----------+
mysql> show variables like 'general_log';+---------------+-------+| Variable_name | Value |+---------------+-------+| general_log | OFF |+---------------+-------+
下边开启一般查询日志并查看日志存放的位置。
mysql> SET GLOBAL general_log=on;Query OK, 0 rows affectedmysql> show variables like 'general_log_file';+------------------+---------------------------------------------------+| Variable_name | Value |+------------------+---------------------------------------------------+| general_log_file | /usr/local/mysql/data/iZ2zebfzaequ90bdlz820sZ.log |+------------------+---------------------------------------------------+
执行一条查询 SQL 看看日志内容的变化。
mysql> select * from t_config;+---------------------+------------+---------------------+---------------------+| id | remark | create_time | last_modify_time |+---------------------+------------+---------------------+---------------------+|1325741604307734530| 我是广播表 |2020-11-09 18:06:44| 2020-11-09 18:06:44 |+---------------------+------------+---------------------+---------------------+
我们看到日志内容详细的记录了所有执行的命令、SQL、SQL 的解析过程、数据库设置等等。
一般查询日志
error log(错误日志)
error log 应该是 MySQL 中最好理解的一种日志,主要记录 MySQL 服务器每次启动和停止的时间以及诊断和出错信息。
默认情况下,该日志功能是开启的。通过如下命令查找错误日志文件的存放路径:
mysql> SHOW VARIABLES LIKE 'log_error';+---------------+----------------------------------------------------------------+| Variable_name | Value |+---------------+----------------------------------------------------------------+| log_error | /usr/local/mysql/data/LAPTOP-UHQ6V8KP.err |+---------------+----------------------------------------------------------------+
注意:错误日志中记录的可并非全是错误信息,像 MySQL 如何启动 InnoDB 的表空间文件、如何初始化自己的存储引擎,初始化 buffer pool 等等,这些也记录在错误日志文件中。
总结
MySQL 作为我们工作中最常接触的中间件,熟练使用只算是入门,如果要在简历写上一笔精通,还需要深入了解其内部工作原理,而这7种日志也只是深入学习过程中的一个起点,学无止境,兄嘚干就完了!