首页 > 数据库 >浅析MySQL中的ACID实现

浅析MySQL中的ACID实现

时间:2024-03-16 11:04:00浏览次数:24  
标签:事务 log InnoDB 提交 MySQL ACID redo 浅析 隔离

浅析MySQL中的ACID实现


MySQL的InnoDB存储引擎通过多种底层机制来实现 ACID(Atomicity, Consistency, Isolation, Durability) 事务特性,这些机制构成了事务处理的基石,因此在这里做一个汇总分析。

一、原子性 (Atomicity)

原子性保证事务中的所有操作要么全部成功,要么全部失败。通过结合redo log和undo log的机制,InnoDB存储引擎能够确保在任何情况下,事务要么全部成功完成,要么完全回滚,不会出现部分成功的情况,从而实现了事务的原子性。

Undo Log(回滚日志)

当一个事务对数据库进行修改时(如INSERT、UPDATE或DELETE操作),InnoDB首先会产生对应的Undo Log记录。

Undo Log记录了原始数据的版本以及执行逆向操作所需的足够的信息,以便在需要回滚事务时恢复到事务开始前的状态。

Redo Log(重做日志)

在事务执行过程中,对数据页所做的所有更改都会先写入内存中的redo log buffer。

当事务提交时,并非立即更新磁盘上的实际数据文件,而是将redo log buffer中的内容刷新到磁盘上的redo log文件(ib_logfile*)中。

Redo Log确保即使在系统崩溃的情况下,也能通过重放这些日志来恢复未完成的事务更改,从而保证事务的持久性(在下面持久性中也会重复讲到),而这也是原子性实现的一部分。当redo log的内容被安全地刷到磁盘后,事务才能被认为是真正提交。

事务提交流程

  1. 事务开始时,分配新的事务ID并开始记录相应的undo和redo日志。

  2. 执行事务内的SQL语句,每一次修改都伴随生成undo日志,并将修改操作的redo信息写入redo log buffer。

  3. 当事务准备提交时,会先确保redo log buffer中的内容被刷新到磁盘,这个过程被称为“预写日志”(Write-Ahead Logging, WAL)策略。

  4. 确保redo log已经落盘之后,事务才会被标记为已提交状态,此时undo日志可以在新的事务开始之前被清理掉(对于已经提交的数据,不再需要保留undo日志)。

异常处理与回滚

如果事务在执行过程中遇到错误或者手动调用ROLLBACK,InnoDB会使用undo log来回滚已做的更改,撤销事务的影响。

回滚操作按照undo log中的逆序逐步执行,直到数据恢复到事务开始前的状态。

二、一致性 (Consistency)

一致性保证了数据库总是在符合特定业务规则的状态下。这主要是由应用层的逻辑以及数据库约束和触发器共同维护的。InnoDB存储引擎可以在并发环境下有效保障事务处理前后数据的一致性,确保数据库从一个一致状态转换到另一个一致状态。

ACID中的其他属性支持一致性

原子性保证了事务要么全部执行成功,要么全部回滚,避免了数据处于中间状态的问题。

隔离性通过不同的隔离级别(如读未提交、读已提交、可重复读和串行化)防止并发事务间的相互影响,使得每个事务在自己的视图中看到的数据是一致的。

事务隔离级别与一致性读

在可重复读隔离级别下,InnoDB使用多版本并发控制(MVCC)技术。每个事务看到的是一个快照,即事务开始时数据库的状态,这样就避免了脏读和不可重复读问题,有助于保持数据一致性。

约束检查

InnoDB在事务执行过程中以及提交前会进行各种完整性约束检查,包括但不限于:主键约束(Primary Key)、唯一约束(Unique Key)、外键约束(Foreign Key)、检查约束(Check Constraints)等,这些约束能够确保数据满足预定义的业务规则。

触发器和存储过程

MySQL还支持触发器(Triggers)和存储过程(Stored Procedures),它们能够在事务执行的关键点执行特定逻辑,以确保业务规则得到遵守,从而维护数据一致性。

两阶段锁定(2PL)

InnoDB采用悲观锁策略,在事务执行期间对要修改的数据加锁,并且在事务结束前不释放这些锁,直到事务提交或回滚。这有助于防止多个事务同时修改同一数据导致的一致性问题。

三、隔离性 (Isolation)

隔离性防止不同事务之间的相互干扰。InnoDB能够在保证数据正确性和并发性能的同时,有效实现不同事务间的隔离,以满足不同业务场景下的需求。

事务隔离级别

读未提交(Read Uncommitted): 一个事务可以读取到其他事务尚未提交的修改。可能会发生脏读,即事务读取到了随后可能被回滚的数据。

读已提交(Read Committed): 一个事务只能读取到已经提交的数据。避免了脏读,但在同一个事务内多次执行相同的查询可能会得到不同的结果,即发生了不可重复读现象。

可重复读(Repeatable Read): MySQL默认的事务隔离级别。事务在整个执行过程中看到的数据视图是一致的,对于同一事务内多次执行的相同查询语句,其结果总是相同的。

串行化(Serializable): 事务按照顺序依次执行,完全避免了脏读、不可重复读和幻读等问题。

隔离性实现

锁机制

InnoDB支持行级锁定,当一个事务修改一行数据时,会对这行数据加锁。根据不同的SQL操作和事务隔离级别,可能会使用共享锁(读锁)、排他锁(写锁)或意向锁等不同类型的锁。

在可串行化(Serializable)隔离级别下,虽然不是直接采用行级锁,但InnoDB会更严格地控制事务之间的并发访问,以避免幻读现象。

多版本并发控制(MVCC)

在“读已提交”(Read Committed)和“可重复读”(Repeatable Read)隔离级别下,InnoDB使用MVCC来提供非锁定读操作,使得在大部分情况下读操作不需要获取任何锁。

MVCC通过对每一行记录保存多个版本,并为每个事务分配一个唯一的事务ID(称为事务视图),使得事务可以查看到自己开始时的数据快照,从而避免了脏读、不可重复读的问题。

Next-Key Locks

在“可重复读”隔离级别下,为了防止幻读问题,InnoDB对索引记录和间隙同时进行锁定,这种锁定被称为Next-Key Locks。它不仅锁定当前行,还锁定该行前后的间隙,确保在同一事务中多次执行相同查询的结果一致。

一致性非锁定读

可重复读隔离级别下,对于只读事务,InnoDB允许事务读取其他事务已经提交的更改,而不会阻塞这些事务的提交,这就是“一致性非锁定读”。

四、持久性 (Durability)

持久性确保一旦事务成功提交,其对数据库所做的更改将会一直存在,即便遇到硬件故障、系统崩溃等情况也能在数据库重启后得到恢复。

Redo Log(重做日志)

  • Redo Log是保证持久性的核心机制。在事务执行过程中,对数据库所做的更改首先会被记录到内存中的redo log buffer中。

  • 当事务提交时,并非立即更新磁盘上的数据文件,而是将redo log buffer的内容刷新到磁盘上的redo log文件(ib_logfile*)中。这个过程被称为“预写日志”(Write-Ahead Logging, WAL)策略,即先写日志再修改数据

  • 确保redo log被安全地刷入磁盘后,事务才会被认为已经提交。这样即使在系统崩溃的情况下,也能通过重放这些redo log恢复尚未写入数据文件的事务操作。

Double Write Buffer

为了防止在操作系统缓存或I/O子系统层次发生故障导致数据页损坏,新写入的数据页首先被复制到一个连续的物理区域(double write buffer),然后才写入实际的数据文件,从而提高了数据页的恢复能力

Checkpoint机制

定期或者在某些特定条件触发下,InnoDB会将脏页(已被修改但未写回磁盘的数据页)从缓冲池刷回到磁盘上的数据文件,以减少恢复时间并释放内存资源。

事务提交流程

在事务提交时,InnoDB会确保redo log的持久化(flush至磁盘),然后再提交事务。这一顺序确保了即使在服务器突然宕机的情况下,也能通过redo log进行恢复,使得已提交的事务更改永久保存。

五、技术总结

在MySQL InnoDB存储引擎中,通过各种底层技术和策略的有效结合,得以在支持高并发处理的同时,保证事务的ACID特性,从而确保了数据库操作的可靠性和数据完整性。

日志系统

Redo Log(重做日志): 用于保证事务的持久性原子性,记录了修改数据库的所有操作,并确保在事务提交前将这些更改先持久化到磁盘。

Undo Log(回滚日志): 用于保证事务的原子性一致性,记录了数据旧版本以及撤销事务所需的信息,在事务回滚时用来恢复数据。

并发控制机制

锁机制: 通过行级锁、表级锁、意向锁等不同类型的锁控制并发事务对同一资源的访问,以实现隔离性

多版本并发控制(MVCC): 在特定的隔离级别下,如“读已提交”和“可重复读”,避免锁定读取,提供非锁定读,从而提高并发性能并保持一定程度的一致性隔离性

事务管理与状态跟踪

事务开始时分配事务ID,并在事务执行过程中跟踪其状态及影响的数据变化。

为每个事务创建一个视图,使得事务能够看到自己启动时数据库的状态,以此来维持一致性和实现不同的隔离级别

故障恢复机制

Double Write Buffer: 防止数据页损坏而无法恢复的情况。

Checkpoint机制: 定期或按需将脏页刷回到磁盘,同步内存数据和磁盘数据,优化恢复过程。

标签:事务,log,InnoDB,提交,MySQL,ACID,redo,浅析,隔离
From: https://blog.csdn.net/qq_45902224/article/details/136757573

相关文章

  • MySQL错误-this is incompatible with sql_mode=only_full_group_by完美解决方案
    解决方案一:使用函数ANY_VALUE()包含报错字段SELECTANY_VALUE(ID),USER_ID,ANY_VALUE(problems),ANY_VALUE(last_updated_date)FROMt_iov_help_feedbackGROUPBYUSER_ID; 解决方案二:通过sql语句暂时性修改sql_mode去掉ONLY_FULL_GROUP_BY,重新设置SET@@global.sql_m......
  • 智慧医养大数据公共服务系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图 项目介绍随着老龄化社会的到来和大数据技术的发展,智慧医养结合的公共服务系统成为社会关注的热点。这一系统能够集成医疗、养老、健康管理等数据,通过智能分析和处理,......
  • 专利管理系统的设计与实现-年费管理(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图 项目介绍在知识产权高度重视的今天,专利申请成为企业和个人保护创新成果的重要手段。随之而来的是专利年费管理的复杂性,如何高效、准确地处理这些费用成为专利管理中......
  • 药品销售管理系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图 项目介绍随着医药行业的快速发展,药品销售的管理日益复杂化,对于系统化、自动化的药品销售管理系统需求不断增加。此系统可以实现对药品库存、销售情况、顾客信息及销......
  • java毕业设计夕阳红养老院系统(springboot+mysql+jdk1.8+meven)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着社会的发展和人口老龄化的加剧,养老问题逐渐成为社会关注的焦点。传统的家庭养老模式已无法满足日益增长的养老需求,特别是对于独居老人和失能老人来说,......
  • 高性能 数据库连接池 HikariCP | MySQL 最佳性能实践
    ......
  • [mysql必备面试题]-mysql索引(B+ Tree )
    一B+Tree原理 1.数据结构BTree指的是BalanceTree,也就是平衡树。平衡树是一颗查找树,并且所有叶子节点位于同一层。B+Tree是基于BTree和叶子节点顺序访问指针进行实现,它具有BTree的平衡性,并且通过顺序访问指针来提高区间查询的性能。在B+Tree中,一个节点......
  • MySQL的四个事务隔离级别有哪些?各自存在哪些问题?
    前言大家应该都知道mysql的事务有四个隔离级别,但是他们分别是什么隔离级别并且会带来什么问题呢?接下来我为大家一一揭晓,通过图解的方式方便大家理解。一、读未提交(ReadUncommitted)1、这个是隔离级别最低的。2、顾名思义,可以看出来就是一个事务可以读取另外一个未提交事务......
  • 连接MySQL报错,is not allowed to connect to this MySQL server
    问题描述:        本机装的MySQL数据库,本机可以正常连接,其他机器访问报错,isnotallowedtoconnecttothisMySQLserver,防火墙等其他策略均配置没问题。  解决方案:    出现该问题的原因是,MySQL数据库只允许自身所在的本机器连接,不允许远程连接。1、......
  • mysql备份脚本
    !/bin/bash备份路径db_backup_path="/data/backup"备份的数据库db_name=("live_net")用户名db_user="root"密码db_pass="[email protected]"gzip文件解压缩密码gz_des_pass="fff@20210326"压缩文件前缀prefix=“credit"日志路径log_path=&quo......