本文全面解析MySQL数据库事务的核心机制,深入探讨事务的ACID特性、生命周期管理、隔离级别原理及InnoDB存储引擎的事务工作流程。涵盖事务的原子性、一致性、隔离性和持久性实现原理,详细分析不同事务隔离级别的应用场景和性能影响,并揭示InnoDB如何通过redo log、undo log、MVCC等机制保障事务的可靠执行。为数据库开发人员和管理员提供完整的事务理解和优化指导。
1.事务概念
-
事务(Transaction)可以更通俗的理解为交易,所以事务会伴随着交易类的业务类型出现(工作模式);
-
现实生活中存在很多的交易行为,比如:物换物的等价交换、货币换物的等价交换、虚拟货币换物(虚拟物品)的等价交换;
-
因此就需要考虑如何保证现实生活中交易过程的和谐,一般会有法律、道德等方面规则进行约束;
-
而在数据库服务中为了保证线上交易的"和谐",便加入了"事务"工作机制。
事务是数据库中处理交易类业务的核心机制,将一系列操作作为一个不可分割的工作单元。与现实生活中交易需要法律和道德约束类似,数据库事务通过ACID特性来保证数据操作的"和谐"与可靠。
2.事务特性
2.1 原子性(Atomicity)
-
原子性表示一个事务生命周期中的DML语句,要么全成功要么全失败,不可以出现中间状态;
-
语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;
-
实现主要基于undo log
sh
Begin:DML01 DML02 DML03 Commit;
2.2 一致性(Consistency)
- 一致性表示一个事务发生前、中、后,数据都最终保持一致,即读和写都要保证一致性;
- 事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障;
sh
CR + Double write
2.3 隔离性(Isolation)
- 隔离性表示一个事务操作数据行的时候,不会受到其他事务的影响,主要利用锁机制来保证隔离性;
2.4 持久性(Durability)
-
持久性表示一旦事务进行了提交,即可永久生效(落盘)
-
保证事务提交后不会因为宕机等原因导致数据丢失;
实现主要基于redo log -
事务ACID相关知识官方说明:https://dev.mysql.com/doc/refman/8.0/en/mysql-acid.html
3.事务生命周期
- 在运用事务机制完成相关工作任务时,对于事务使用是存在生命周期概念的,标准显示的事务生命周期控制语句有:
sh
# 开启事务机制
begin;
start transaction;
# 提交事务任务
commit;
# 回滚事务操作
rollback;
说明:事务生命周期中,只能使用DML语句,其中包括:select、update、delete、insert;DDL语句会隐式进行提交
4.事务提交方式
4.1 自动提交方式(auto_commit)
sql
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
-- 在事务自动提交功能设置修改时,设置为1表示开启自动提交,设置为0表示关闭自动提交
# 临时关闭事务自动提交功能
mysql> set global autocommit=0;
-- 配置调整后,重新登录mysql数据库生效
# 永久关闭事务自动提交功能
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
autocommit=0
-- 配置调整后,重新启动mysql数据库生效
autocommit 开启与关闭优缺点:
| 序号 | 参数配置 | 优势 |
|---|---|---|
| 情况01 | autocommit=0 关闭事务自动提交 | 可以编写多个关联的DML,进行一次性提交操作,若出现异常可以回滚 符合原子特性 |
| 劣势 | ||
| 可能出现多个关联的DML,只是完成了部分操作,这时就可能等待状态 基于隔离特性,操作的数据表或数据行就会进入锁定状态 | ||
| 参数配置 | 优势 | |
| 情况02 | autocommit=1 开启事务自动提交 | 可以出现多个关联的DML,逐行操作自动提交,就可以不用处于锁等待状态 |
| 劣势 | ||
| 可能出现多个关联的DML,,每执行一条就进行提交,会造成多个语句执行不符合原子性 |
4.2 隐式提交方式
在进行事务操作时,需要注意操作语句必须都是DML语句,如果中间插入了DDL语句,也会造成之前的事务操作自动提交;
sql
begin; DML1; DML2; DDL1; COMMIT; DML3; COMMIT;
-- 这种情况出现会破坏原本事务的原子性
隐式自动提交方式语句:
在出现隐式自动提交时,可能导致提交的非事务语句有:
| 序号 | 语句类型 | 涉及命令 |
|---|---|---|
| 01 | DDL语句类型 | alter、create、drop |
| 02 | DCL语句类型 | grant、revoke、set password |
| 03 | 锁定语句类型 | lock tables、unlock tables |
| 04 | 其他语句类型 | truncate table、load data infile、select for update |
说明:在多个数据库会话窗口中,A窗口的所有事务性DML操作,不会受到B窗口的非事务语句影响,同一会话窗口会有影响;
5.事务隔离级别
数据库事务隔离级别主要作用是实现事务工作期间,数据库操作读的隔离特性,所谓读的操作就是将数据页可以调取到内存;
然后可以读取数据页中相应数据行的能力,并且不同事务之间的数据页读操作相互隔离;
可以简单理解为:一个事务在对数据页中数据行做更新操作时,在没有更新提交前,另一个事务此时是不能读取数据页中数据行内容的;
对于数据库存储事务隔离级别包括4种,可以通过操作命令查看获取当前使用的隔离级别:
sql
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
mysql> set global transaction_isolation='READ-UNCOMMITTED';
常用的事务隔离级别类型:
5.1 RU(READ-UNCOMMITTED 表示读未提交)
可以读取到事务未提交的数据,隔离性差,会出现脏读(当前内存读),不可重复读,幻读问题;
5.2 RC(READ-COMMITTED 表示读已提交)可用
可以读取到事务已提交的数据,隔离性一般,不会出现脏读问题,但是会出现不可重复读,幻读问题;
5.3 RR(REPEATABLE-READ 表示可重复读)默认
可以防止脏读(当前内存读),防止不可重复读问题,防止会出现的幻读问题,但是并发能力较差;
会使用next lock锁进制,来防止幻读问题,但是引入锁进制后,锁的代价会比较高,比较耗费CPU资源,占用系统性能;
5.4 SR(SERIALIZABLE 可串行化)
隔离性比较高,可以实现串行化读取数据,但是事务的并发度就没有了;
这是事务的最高级别,在每条读的数据上,加上锁,使之不可能相互冲突.
事务隔离级别官方链接:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html
名词解读分析
- 脏读:在一个事务窗口中,可以读取到别人没有提交的数据信息(可以看到内存中的数据);
- 不可重复读:在一个事务中,利用相同的语句多次查询,获取的数据信息是不同的;
6.事务工作流程
根据存储事务的工作流程原理,来了解如何保证事务的ACID特性,利用了MySQL数据库的哪些工作机制;
名称解释:
sh
1. redo log Disk
重做日志,当出现异常情况,内存中数据直接写入磁盘失败时,可以通过重启数据库服务,读取此文件修复数据信息;文件存储表项为:ib_logfile0~N 默认48M,轮询使用
2. redo log buffer mem
重做日志生成缓冲区,相当于redo log的内存区域。redo log文件与redo log buffer是有IO关系的;
事务修改提交后:redo log buffer -> redo log,表示写入数据到redo log;
事务操作恢复时:redo log -> redo log buffer,表示读取数据从redo log;
3. tablespace file Disk
存储表数据行和索引等信息的文件,含有表空间所有数据文件;ibd
4. Innodb buffer pool mem
数据缓冲区,主要用于缓冲事务要处理的数据和索引信息,tablespace文件与buffer pool是有IO关系的;
5. LSN
日志序列号,在buffer pool中有数据页信息的变化就会记录到redo log buffer中,主要记录变化了多少字节量;
利用LSN记录相应数据页的日志变化量(LSN+变化字节量),也可以理解为记录的是日志量的变化;
MySQL每次数据库启动,都会比较磁盘数据页和redolog的LSN,必须要求两者一致,数据库才能正常启动;
5. WAL(Write Ahead Log)
redo日志生成记录优先于数据页写入到磁盘的过程,并且是支持预写入机制(group commit)的;
6. Dirty page
表示在内存进行修改的数据页,在redo buffer中会记录数据页的数据量的变化,此时在数据页还未最终写入到磁盘中时,就称之为脏页,所以一般所谓的脏读就是读取脏页的数据页信息;
7. CheckPoint
检查点,就是将脏页刷写到磁盘的动作;
8. DB_TRX_ID(6字节)
事务ID号,InnoDB会为每一个事务生成一个事务号(由事务管理器管理TM),伴随着整个事务生命周期其中事务ID号码信息,在redo和undo日志文件中都会有相应的标识;
9. DB_ROLL_PTR(7字节)
回滚指针,在rollback时会使用undo日志回滚已修改的数据,DB_ROLL_PTR会指向此次事务的回滚业务点;从而找到undo上的相应的日志信息;
数据库名词解释官方参考:https://dev.mysql.com/doc/refman/8.0/en/glossary.html
工作流程:
sh
1. redo保证了ACID中的D特性,另外A C也有间接关联;
说明:利用redo Log重做日志功能可以保证事务的D特性,基于可以丢内存数据,但是不可以丢操作事务日志的原则;
2. undo保证了ACID中的A特性,同时C和I的特性也有关系;
说明:利用undo Log重做日志功能可以保证事务的A特性,基于先进行数据页前滚操作恢复脏页,在进行回滚操作恢复操作前事务;
3. cr+dw保证了ACID中的C特性
InnoDB crash recovery:数据库意外宕机时刻,通过redo前滚+undo回滚保证数据的最终一致;
InnoDB doubewrite buffer:早期默认存储在ibdataN中,解决数据页写入不完整;DWB一共2M,分两次。每次1M写入;
4. 事务中的I特性如何保证 保证读写隔离性
主要对数据库服务并发访问资源的保护,在并发事务工作期间,防止事务与事务之间的资源争抢(相互影响);
利用MVCC机制隔离(只能保证读的隔离)
利用隔离级别和锁机制保证写的隔离
7.总结
事务机制是数据库系统的基石,InnoDB通过精心设计的Redo Log、Undo Log、MVCC和锁机制,实现了完整的ACID特性保障。深入理解事务的工作原理,对于设计高性能、高可靠的数据库应用至关重要。
通过合理配置事务参数、选择适当的隔离级别、优化事务设计,可以在保证数据一致性的同时,最大限度地提升系统并发性能。掌握事务机制不仅有助于日常开发,更是进行数据库性能调优和故障排查的基础技能。
在分布式系统和云原生架构日益普及的今天,事务机制的理解和运用显得更加重要,它是构建可靠数据服务的关键技术保障。