其他
超干货!为了让你彻底弄懂 MySQL 事务日志,我通宵肝出了这份图解!
The following article is from 业余码农 Author Amazing10
1 关系型数据库与NoSQL
https://db-engines.com/en/ranking
2 MySQL简介
介绍
体积小、速度快; 代码开源,采用了 GPL 协议,可以修改源码来开发自己的 MySQL 系统; 支持大型的数据库,可以处理拥有上千万条记录的大型数据库; 使用标准的 SQL 数据语言形式,并采用优化的 SQL 查询算法,有效地提高查询速度; 使用 C 和 C++ 编写,并使用多种编译器进行测试,保证源代码的可移植性; 可运行在多个系统上,并且支持多种语言; 核心程序采用完全的多线程编程,可以灵活地为用户提供服务,充分利用CPU资源。
逻辑架构
连接层: 负责处理客户端的连接以及权限的认证。 服务层: 定义有许多不同的模块,包括权限判断,SQL接口,SQL解析,SQL分析优化, 缓存查询的处理以及部分内置函数执行等。MySQL的查询语句在服务层内进行解析、优化、缓存以及内置函数的实现和存储。 引擎层: 负责MySQL中数据的存储和提取。MySQL中的服务器层不管理事务,事务是由存储引擎实现的。其中使用最为广泛的存储引擎为InnoDB,其它的引擎都不支持事务。 存储层: 负责将数据存储与设备的文件系统中。
3 MySQL事务
提交:commit,将事务执行结果写入数据库。
回滚:rollback,回滚所有已经执行的语句,返回修改之前的数据。
原子性(Atomicity) :语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log日志实现的。 持久性(Durability :保证事务提交后不会因为宕机等原因导致数据丢失;实现主要基于redo log日志。 隔离性(Isolation) :保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR,RR的实现主要基于锁机制、数据的隐藏列、undo log和类next-key lock机制。 一致性(Consistency) :事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障。
原子性
持久性
隔离性
按照粒度划分:行锁、表锁、页锁 按照使用方式划分:共享锁、排它锁 按照思想划分:悲观锁、乐观锁
粒度:指数据仓库的数据单位中保存数据的细化或综合程度的级别。细化程度越高,粒度级就越小;相反,细化程度越低,粒度级就越大。
行锁:粒度最小的锁,表示只针对当前操作的行进行加锁;
表锁:粒度最大的锁,表示当前的操作对整张表加锁;
页锁:粒度介于行级锁和表级锁中间的一种锁,表示对页进行加锁。
表锁在操作数据时会锁定整张表,因而并发性能较差; 行锁则只锁定需要操作的数据,并发性能好。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源。
MVCC:Multi-Version Concurrency Control,即多版本的并发控制协议。
next-key lock
机制实现的。next-key lock
实际上就是行锁的一种,只不过它不只是会锁住当前行记录的本身,还会锁定一个范围。比如上面幻读的例子,开始查询0<阅读量<100的文章时,只查到了一个结果。next-key lock
会将查询出的这一行进行锁定,同时还会对0<阅读量<100这个范围进行加锁,这实际上是一种间隙锁。间隙锁能够防止其他事务在这个间隙修改或者插入记录。这样一来,就保证了在0<阅读量<100这个间隙中,只存在原来的一行数据,从而避免了幻读。间隙锁:封锁索引记录中的间隔
next-key lock
能够避免幻读问题,但却并不是真正的可串行化隔离。再来看一个例子吧。在T6时间,事务A提交事务之后,猜一猜文章A和文章B的阅读量为多少?
一致性
4 MySQL日志系统
重做日志(redo log)
write_pos
标志到了日志结尾时,会从结尾跳至日志头部进行重新循环写入。所以redo log的逻辑结构并不是线性的,而是可看作一个圆周运动。write_pos
与checkpoint
中间的空间可用于写入新数据,写入和擦除都是往后推移,循环往复的。write_pos
追上checkpoint
时,表示redo log日志已经写满。这时不能继续执行新的数据库更新语句,需要停下来先删除一些记录,执行checkpoint
规则腾出可写空间。checkpoint规则:checkpoint触发后,将buffer中脏数据页和脏日志页都刷到磁盘。
脏数据:指内存中未刷到磁盘的数据。
buffer pool
,这是在内存中分配的一个区域,包含了磁盘中部分数据页的映射,作为访问数据库的缓冲。当请求读取数据时,会先判断是否在缓冲池命中,如果未命中才会在磁盘上进行检索后放入缓冲池;
当请求写入数据时,会先写入缓冲池,缓冲池中修改的数据会定期刷新到磁盘中。这一过程也被称之为刷脏 。
buffer pool
中的数据,还会在redo log中记录这次操作;当事务提交时,会根据redo log的记录对数据进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复,从而保证了事务的持久性,使得数据库获得crash-safe
能力。redo log buff
,二是保存在磁盘上的redo log日志文件redo log file
。redo log buffer
中的日志写入redo log file
的过程中都会调用一次操作系统的fsync
操作。fsync函数:包含在UNIX系统头文件#include <unistd.h>中,用于同步内存中所有已修改的文件数据到储存设备。
os buffer
。redo log日志的写入过程可见下图。redo log日志刷盘流程
二进制日志(binlog)
物理的日志可看作是实际数据库中数据页上的变化信息,只看重结果,而不在乎是通过“何种途径”导致了这种结果; 逻辑的日志可看作是通过了某一种方法或者操作手段导致数据发生了变化,存储的是逻辑性的操作。
crash recovery
,保证MySQL宕机后的数据恢复;而binlog是基于point-in-time recovery
,保证服务器可以基于时间点对数据进行恢复,或者对数据进行备份。crash-safe
能力,所以InnoDB引擎就采用了学自于Oracle的技术,也就是redo log,这才拥有了crash-safe
能力。这里对redo log日志和binlog日志的特点分别进行了对比:prepare
状态的写入,二是binlog写入之后commit
状态的写入。crash-safe
能力,因此系统崩溃,数据会恢复成事务开始之前的状态。但是,若在redo log写完时候,binlog写入之前,系统发生了宕机。此时binlog没有对上面的更新语句进行保存,导致当使用binlog进行数据库的备份或者恢复时,就少了上述的更新语句。从而使得id=2
这一行的数据没有被更新。id=2
这一行的数据并没有更新。回滚日志(undo log)
5 主从复制
1. 通过复制实现数据的异地备份,当主数据库故障时,可切换从数据库,避免数据丢失。 2. 可实现架构的扩展,当业务量越来越大,I/O访问频率过高时,采用多库的存储,可以降低磁盘I/O访问的频率,提高单个机器的I/O性能。 3. 可实现读写分离,使数据库能支持更大的并发。 4. 实现服务器的负载均衡,通过在主服务器和从服务器之间切分处理客户查询的负荷。
6 总结
你知道的越多,不知道的也就越多。
看完本文有收获?请转发分享给更多人
推荐关注「数据分析与开发」,提升数据技能
点赞和在看就是最大的支持❤️