文章目录
- 事务四特性
- 预备知识
- checkpoint机制
- redo日志
- redo的流程
- 事务提交后什么时候进行刷盘
- undo日志:数据还未被修改、也是备份
- Undo日志的作用
- undo的存储结构
- 回滚段与事务
- 回滚段中的数据分类
- undo的类型
- undo log的生命周期
- MVCC
- 一、 原子性原理
- 如何通过undo日志实现原子性
- 当我们在使用事务操作时
- 二、持久性
- 三、隔离性
- 四、 一致性
事务四特性
MySQL支持四大事务特性,通常缩写为ACID,分别是:
-
原子性(Atomicity): 这意味着一个事务中的所有操作要么全部成功完成,要么全部失败回滚。如果在事务执行过程中发生错误,MySQL将撤销所有对数据库的更改,以确保数据的一致性。原子性确保了数据库处于一种可预测的状态。
-
一致性(Consistency): 这意味着在事务开始和结束时,数据库必须满足一致性约束。这意味着事务执行前后,数据库应该从一个一致的状态转变为另一个一致的状态。如果某个事务破坏了一致性约束,系统将回滚事务以确保数据的一致性。
- 一致性通常比价难理解,比如说从你有100元,去银行提交一个取两百元的事务,结束之后,你有-100元。这是不符合我们的约束的,银行将会回滚你的操作。
-
隔离性(Isolation): 隔离性是指多个并发事务之间应该是相互隔离的,一个事务的执行不应影响其他事务的执行。MySQL提供了不同的隔离级别,如读未提交、读已提交、可重复读和串行化,以满足不同的需求。不同的隔离级别会影响事务的性能和并发行为。
-
持久性(Durability): 持久性确保一旦事务提交,对数据库的更改将被永久保存,即使系统发生故障或重启。这是通过将事务日志写入非易失性存储设备来实现的,以便在系统崩溃后可以恢复数据。
预备知识
checkpoint机制
MySQL的checkpoint(检查点)机制是数据库管理系统用于定期将内存中的数据持久化到磁盘的过程。这个机制确保了数据库的一致性和持久性,同时也有助于优化性能。以下是关于MySQL的checkpoint机制的一些关键信息:
-
目的: Checkpoint的主要目的是将内存中的数据页(包括已修改但尚未写入磁盘的数据页)刷新到磁盘,从而确保数据库的一致性和持久性。在数据库发生崩溃或故障时,已经写入磁盘的数据页可以用于数据库的恢复。
-
触发时机: Checkpoint不是实时进行的,而是按计划和需要执行的。MySQL使用一种叫做"InnoDB Checkpoint"的机制来管理这一过程。Checkpoints通常在以下情况下触发:
- 后台线程定期触发,以确保数据被定期写入磁盘。
- 当日志文件空间不足或其他需要释放磁盘空间的情况下。
- 当执行FLUSH TABLES、FLUSH LOGS、或其他相关命令时。
-
性能影响: Checkpoint会涉及磁盘写入操作,因此可能会对性能产生一定影响,特别是在大量写入操作时。合理调整和优化Checkpoint参数可以减轻性能影响,如调整
innodb_max_dirty_pages_pct
和innodb_io_capacity
等参数。 -
日志文件: Checkpoint期间,MySQL还会在Redo日志中记录相关信息,以确保可以在需要时恢复到Checkpoint之后的状态。这有助于数据库的恢复。
-
InnoDB存储引擎: Checkpoint机制主要与InnoDB存储引擎相关,因为InnoDB是MySQL中常用的存储引擎之一。其他存储引擎可能具有不同的Checkpoint实现。
Checkpoint机制有助于防止数据丢失,并支持数据库的可靠性和恢复。
redo日志
InnoDB存储引擎 是以页存储(表空间中申请到的一个固定大小的内容),redo日志由;两部分组成:
- 重做日志的缓冲 (redo log buffer) ,保存在内存中,是易失的。
- 重做日志文件 (redo log file) ,保存在硬盘中,是持久的。
-
Redo日志的存储: MySQL的Redo日志文件以二进制格式存储在磁盘上,通常在MySQL数据目录中的多个Redo日志文件中(通常以
ib_logfile
的形式存在)。这些文件是循环写入的,意味着当一个文件写满后,MySQL会切换到下一个文件。 -
Redo日志的写入时机: Redo日志记录在事务进行中的数据修改,但是这些记录并不是在每个SQL语句执行时都写入。通常,MySQL在事务提交时将Redo日志记录写入磁盘,以确保已提交事务的修改得到持久保存。
-
用途: Redo日志主要用于数据库恢复和复制。在数据库发生崩溃或重启时,MySQL可以使用Redo日志来还原数据库到最后一次提交的状态,以防止数据丢失。此外,MySQL的主从复制(replication)机制也使用Redo日志来将主数据库上的更改复制到从数据库上,以保持数据的同步。
-
Redo日志文件大小和性能: Redo日志文件的大小和数量是可配置的,通常可以通过MySQL的配置参数进行调整。适当配置Redo日志文件大小可以在一定程度上影响系统的性能,因为较大的Redo日志文件可以容纳更多的事务记录,但也会增加磁盘写入的开销。
总之,MySQL的Redo日志是数据库事务管理的关键组成部分,它确保了数据的一致性和持久性,同时也支持数据库的恢复和复制功能。
redo的流程
第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加
写的方式
第4步:定期将内存中修改的数据刷新到磁盘中
事务提交后什么时候进行刷盘
InnoDB给出 innodb_flush_log_at_trx_commit
参数,该参数控制 commit提交事务
时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:
设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日
志的同步)
第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加
写的方式
第4步:定期将内存中修改的数据刷新到磁盘中
设置为1 :表示每次事务提交时都将进行同步,刷盘操作( 默认值 )
设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由os自
己决定什么时候同步到磁盘文件。
undo日志:数据还未被修改、也是备份
redo log
是事务持久性的保证,undo log
是事务原子性的保证。在事务中 更新数据 的 前置操作 其实是要先写入一个 undo log
。
Undo日志的作用
- 作用1:回滚数据
- Undo日志用于记录在事务执行期间所做的更改,以便在回滚时能够恢复到事务开始之前的状态。
- 作用2:MVCC
- 允许多个事务同时访问相同的数据而不会互相干扰。每个事务在读取数据时会看到自己事务开始之前的快照,而undo日志用于维护这些数据的不同版本。
undo的存储结构
InnoDB对undo log的管理采用段的方式,也就是 回滚段(rollback segment) 。每个回滚段记录了1024 个 undo log segment ,而在每个undo log segment段中进行 undo页 的申请。
- 在 InnoDB1.1版本之前 (不包括1.1版本),只有一个rollback segment,因此支持同时在线的事务限制为 1024 。虽然对绝大多数的应用来说都已经够用。
- 从1.1版本开始InnoDB支持最大 128个rollback segment ,故其支持同时在线的事务限制提高到了 128*1024
mysql> show variables like 'innodb_undo_logs';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| innodb_undo_logs | 128 |
+------------------+-------+
回滚段与事务
- 每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。
- 当一个事务开始的时候,会制定一个回滚段,在事务进行的过程中,当数据被修改时,原始的数据会被复制到回滚段。
- 在回滚段中,事务会不断填充盘区,直到事务结束或所有的空间被用完。如果当前的盘区不够用,事务会在段中请求扩展下一个盘区,如果所有已分配的盘区都被用完,事务会覆盖最初的盘区或者在回滚段允许的情况下扩展新的盘区来使用。
- 回滚段存在于undo表空间中,在数据库中可以存在多个undo表空间,但同一时刻只能使用一个undo表空间。
- 当事务提交时,InnoDB存储引擎会做以下两件事情:
- 将undo log放入列表中,以供之后的purge操作
- “purge” 操作:清除或删除不再需要的数据或日志
- 判断undo log所在的页是否可以重用,若可以分配给下个事务使用
- 将undo log放入列表中,以供之后的purge操作
回滚段中的数据分类
- 未提交的回滚数据(uncommitted undo information)
- 已经提交但未过期的回滚数据(committed undo information)
- 事务已经提交并过期的数据(expired undo information)
undo的类型
在InnoDB存储引擎中,undo log分为:
- insert undo log
- update undo log
undo log的生命周期
在MySQL中,Undo Log(回滚日志)用于存储事务执行过程中对数据的修改,以便在事务回滚或MVCC(多版本并发控制)中提供一致性视图。Undo Log的生命周期主要包括以下阶段:
-
事务开始: 在事务开始时,MySQL会为事务分配一个唯一的事务标识(Transaction ID,简称XID)。每个事务都有自己的Undo Log。
-
数据修改: 在事务执行过程中,如果对表的数据进行了修改(插入、更新、删除等操作),相应的变更会记录在Undo Log中。Undo Log中记录了修改之前的数据信息,以便在回滚时恢复。
-
MVCC使用: 如果启用了MVCC,Undo Log还用于提供一致性读取。在读取数据时,可以根据Undo Log中的信息获取对应版本的数据,以实现事务隔离级别。
-
事务提交: 当事务成功提交时,Undo Log中的相关信息可以被丢弃,因为此时对应的数据已经成为当前版本,不再需要回滚到旧版本。但是,一些存储引擎(如InnoDB)可能并不立即删除Undo Log的数据,而是等待一定的时间或某些条件满足后再进行删除。
-
事务回滚: 如果事务回滚,Undo Log中的修改会被用来撤销事务对数据的影响,将数据恢复到事务开始前的状态。
-
Undo Log空间重用: 当Undo Log中的空间不再需要时,MySQL可以将其空间标记为可重用。这通常发生在事务提交后,不再需要保留修改之前的数据。
需要注意的是,Undo Log的生命周期可能会受到配置参数、存储引擎实现等因素的影响。在InnoDB存储引擎中,Undo Log的相关参数可以在配置文件中进行调整。
MVCC
MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库管理系统使用的并发控制机制。它的目标是在多用户同时访问数据库时,提供高并发性和事务隔离性,而不会导致数据冲突。MVCC通过为每个事务创建一个可见的快照版本,而不是直接修改现有数据,来实现这一目标。
MVCC 的主要特点包括:
-
版本号或时间戳: 每个数据行都有一个与之关联的版本号或时间戳。当事务对数据行进行修改时,会将新的版本号或时间戳与之关联。
-
快照读取: 事务在读取数据时,看到的是数据库在其开始时的快照。这意味着即使其他事务在读取或修改同一行数据,当前事务也不会受到影响。每个事务都有自己的事务隔离级别,决定了它能够看到其他事务的哪些变更。
-
旧版本的保存: 当事务对数据行进行修改时,不会直接在原始数据上进行修改,而是创建一个新的版本,并在存储中保留旧版本。这使得多个事务能够同时访问相同的数据行,而不会相互干扰。
-
回滚操作: 如果事务需要回滚,系统可以通过撤销对应版本的修改来还原数据。这通常涉及到Undo日志,Undo日志中记录了事务对数据的修改,以便回滚。
MVCC 的优势在于提高了数据库系统的并发性能,减少了锁竞争的情况。(当然也提高了对内存与磁盘的要求)
一、 原子性原理
如何通过undo日志实现原子性
- MySQL使用Undo日志记录事务对数据的修改,这允许在事务回滚时撤销已经进行的修改。Undo日志确保在事务执行的过程中,可以回滚到事务开始时的状态,从而保持原子性。
- 同时这也表明了:MySQL采用了页的写入方式,即将数据刷新到磁盘上的页(Page)中。
- 这样,在事务执行过程中,数据的修改是在内存中进行的,只有在事务提交时才将修改刷新到磁盘。这有助于提高性能,并且在事务回滚时可以避免对磁盘的不必要写入。
当我们在使用事务操作时
事务是数据库管理系统中一组相关的操作,这些操作要么全部执行成功,要么全部失败回滚。在关系型数据库中,典型的事务处理过程包括开始事务、提交事务、和刷入磁盘。以下是这些步骤的一般流程:
-
开始事务:
- 通过执行SQL语句
BEGIN TRANSACTION
或者数据库连接对象的方法来开始事务。在事务开始时,数据库系统会为该事务分配一个唯一的事务标识(Transaction ID)。
BEGIN TRANSACTION;
或者在一些数据库系统中,事务可以自动开始,例如在执行第一个SQL语句时。
- 通过执行SQL语句
-
执行事务操作:
- 在事务中执行一系列的SQL操作,包括插入、更新、删除等。这些操作在内存中进行,而不会立即影响到磁盘上的数据。
UPDATE table_name SET column1 = value1 WHERE condition; INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...); DELETE FROM table_name WHERE condition;
-
提交事务:
- 如果事务中的所有操作都执行成功,通过执行
COMMIT
语句来提交事务。这将会把事务中的修改应用到数据库,并且将数据持久化到磁盘。
COMMIT;
如果有任何操作失败,可以执行
ROLLBACK
语句来回滚事务,撤销所有的修改。 - 如果事务中的所有操作都执行成功,通过执行
-
刷入磁盘:
- 事务提交后,数据库系统将内存中的修改刷入到磁盘上的数据文件中。这确保了数据的持久性,并且可以通过数据库日志进行故障恢复。
数据库系统通常会采用一种优化策略,将修改聚合成较大的块,以减少对磁盘的频繁写入,提高性能。
总的来说**,开始事务、执行事务操作、提交事务、和刷入磁盘**是构成事务处理过程的关键步骤。这些步骤保证了数据库的一致性和持久性,同时提供了事务回滚的机制,以应对在事务执行过程中可能发生的错误。
每个事务在执行时看到的数据版本是事务开始时的快照。Undo日志用于在需要时生成这些快照,以实现事务的隔离性。不同事务可以同时修改相同的数据,而不会相互干扰,因为每个事务看到的是在其开始时数据库的一致状态。从而达成MVCC(Multi-Version Concurrency Control,多版本并发控制)。
二、持久性
- 首先、数据刷新到磁盘: 数据库系统通常将修改后的数据先保存在内存中,而不是直接写入磁盘。当事务提交时,数据库会将修改的数据页刷新到磁盘上的数据文件。这个过程确保了在事务提交后,相应的数据已经持久化到磁盘。
- 众所周知,操作系统中的IO操作通常耗费大量时间。正因如此,Checkpoint操作变得至关重要。通过定期执行Checkpoint,我们能够在适当的时机将内存中的数据批量写入磁盘,而不是在每个事务提交时都进行大量的IO操作。这种优化策略有助于降低IO的频率,减轻系统开销,防止长时间内大量IO错误的积累。如果不进行这种过渡措施,可能导致数据不仅无法完整保存,还可能损害数据库的一致性和协调性。
三、隔离性
事务之间相互隔离,如何实现相互隔离?还得依靠之前我们说过的MVCC多版本控制,通过对新旧版本的对比,最终合理的放入。不同事务之间的修改不会相互干扰,每个事务看到的是一致的、自己独立的数据视图。
四、 一致性
为什么把一致性放到第四位,因为看了之前的三个特性,可以发现,之前的三类特性都是在给一致性服务的,最后落到实地的还是一致性。
执行事务前后,数据保持一致。
也就是说:指数据库始终处于合法、正确的状态,不管发生了什么样的事务或操作。确保数据库在任何时间点都保持一种合理、可预测的状态。就和一开始举例的银行取钱的经典问题一样。
- Undo日志: InnoDB使用Undo日志记录事务对数据的修改。如果事务需要回滚,系统可以通过Undo日志来撤销已经执行的操作,将数据恢复到事务开始时的状态。Undo日志在一致性的维护中起到了关键作用。
- MVCC(多版本并发控制): InnoDB通过MVCC机制实现事务的隔离性,从而提供了一致性的视图。每个事务在执行时,看到的是数据库在其开始时的快照,而不是实际时刻的数据。这确保了不同事务之间的数据隔离,防止读取未提交的数据。