当前位置: 首页 > article >正文

MySQL事务及实现原理

一、MySQL事务简单介绍
MySQL事务是指一组操作,它们被看作一个单独的工作单元,要么全部成功,要么全部失败回滚。在MySQL中,事务可以确保数据的一致性和完整性。

事务通常由四个关键词来描述:

1、BEGIN 或 START TRANSACTION:标志着事务的开始。
2、COMMIT:表示事务完成,并把所有的修改持久化到数据库。
3、ROLLBACK:表示事务的失败,并且撤销所有对数据库的修改。
4、SAVEPOINT:可以设置事务的一个保存点,可以回滚到此处。
在MySQL中,只有使用了InnoDB存储引擎的表才支持事务。

当执行一系列的SQL语句时,如果其中有一个SQL语句执行失败,则所有SQL语句都会回滚,也就是说之前的所有SQL操作都被撤销,数据库回到之前的状态。而只有当所有SQL语句都执行成功后,它们才会被提交到数据库中,这就保证了数据的一致性。

事务在开发中常用于保证数据的完整性和一致性,例如在进行银行转账时,需要保证从一个账户扣除的金额一定会被转入到另一个账户中,如果出现了其中一个账户扣除了金额而另一个账户没有收到对应的金额的情况,那么这就是一种数据的不一致性。在这种情况下,使用事务可以保证这个问题不会发生,因为要么所有的操作都成功,要么都失败。

二、事务特性ACID介绍

原子性(Atomicity)
事务中的所有操作要么全部成功,要么全部失败回滚。如果有一个操作失败,则整个事务都应该回滚到最初状态。

例如,假设我们有一个银行转账系统。当我们从一个账户转账到另一个账户时,需要确保资金的安全和正确性。如果转账过程中任何一个步骤失败,例如金额不足或接收方账户不存在,则必须回滚到最初状态,确保事务的原子性。

一致性(Consistency)
在事务执行过程中,数据库必须始终保持一致状态。在事务执行的任何时刻,数据库必须满足一组事务的约束条件。

例如,假设我们有一个订单系统。当用户下订单时,订单总金额必须小于用户账户的余额。如果订单总金额大于用户账户的余额,则必须回滚事务,以保持一致性。

隔离性(Isolation)
事务应该在相互隔离的环境中执行,以避免并发执行时可能出现的问题。每个事务都应该以一种完全独立的方式执行,不受其他事务的影响。

例如,如果两个用户在同一时间购买同一件商品,系统必须确保两个用户看到的是正确的库存量,并且不会出现两个用户都买到同一件商品的情况。

持久性(Durability)
一旦事务成功提交,其结果就应该持久保存在数据库中,即使系统崩溃或重新启动,数据也应该仍然存在。

例如,假设我们有一个电子邮件系统。当用户发送电子邮件时,该邮件必须被保存在数据库中,即使系统在发送电子邮件后崩溃,也必须确保该邮件在系统恢复后仍然存在。

需要注意的是,不同的数据库管理系统对事务的实现方式可能会有所不同,因此在使用事务时,需要根据具体的数据库管理系统和应用场景来选择适合的实现方式。

三、事务隔离级别

在没有隔离级别的情况下,可能会发生以下情况:

脏读(Dirty Read):一个事务读取了另一个事务还未提交的数据,如果这个事务回滚,那么读到的数据就是无效的,这种情况称为脏读。
不可重复读(Non-repeatable Read):一个事务在执行过程中多次读取同一数据,由于其他事务对该数据进行了修改,因此这些读取操作得到的结果可能不同,这种情况称为不可重复读。
幻读(Phantom Read):一个事务按照相同的查询条件两次查询,但是得到的结果集却不同。这是因为其他事务对该表进行了新增或删除操作,导致当前事务查询到的结果集不一致,这种情况称为幻读。
这些情况都是由于多个事务之间的数据相互干扰导致的,而隔离级别就是用来解决这些问题的。
 

四、MySQL事务实现原理
(一)事务原理总述
MySQL 事务是基于 InnoDB 存储引擎实现的。MySQL 的事务原理主要包括以下几个方面:

redo log:InnoDB 在执行事务时,会将事务的修改操作记录在 redo log 中,以保证事务的持久性。redo log 记录了每个事务对数据所做的修改,包括修改的行、列和修改前后的值等信息。当事务提交时,会将 redo log 写入到磁盘中,以保证数据的持久性。
undo log:InnoDB 在执行事务时,会将事务的修改操作记录在 undo log 中,以支持事务的回滚和 MVCC 功能。undo log 记录了每个事务对数据所做的修改,包括修改的行、列和修改前的值等信息。当事务需要回滚时,会使用 undo log 中的信息将数据恢复到事务执行前的状态。
MVCC:InnoDB 实现了多版本并发控制(MVCC)来支持事务的隔离性。MVCC 是通过保存多个版本的同一行来实现的,每个版本都有一个唯一的时间戳,表示该版本的生命周期。在事务执行过程中,会根据当前事务的隔离级别确定可见的数据版本,以保证事务之间的隔离。同时也可以保证并发性。
锁机制:InnoDB 通过实现共享锁和排它锁来保证数据的一致性和隔离性。共享锁用于读操作,可以多个事务同时持有;排它锁用于写操作,同一时间只能有一个事务持有。在事务执行过程中,会根据需要自动加锁和解锁,以保证数据的一致性、隔离性和并发性。
事务提交与回滚:InnoDB 支持事务的原子性,一旦事务提交,就会将修改操作写入磁盘中,并释放所有锁。如果事务发生异常或被回滚,会将修改操作回滚,并释放所有锁。
综上所述,MySQL 事务的原理涉及多个方面,包括 redo log、undo log、MVCC、锁机制以及事务提交和回滚等。这些机制共同保证了事务的 ACID 特性,同时也保证了数据的一致性、并发性和持久性。

(二)undo log 原子性分析
undo log 是 InnoDB 存储引擎中用于实现事务回滚和 MVCC 的机制之一,可以保证事务的原子性。其原理如下:

当一个事务需要修改一行数据时,InnoDB 首先将该行数据的原始值拷贝到 undo log 中,然后执行修改操作。如果事务需要回滚,可以使用 undo log 中的原始值将数据恢复到修改前的状态。如果事务提交,则可以将 undo log 中的信息删除。

在事务执行期间,每次对数据进行修改时,InnoDB 将修改前的值保存到 undo log 中,以便在事务回滚时使用。如果事务提交,则将 undo log 中的信息删除,以保证数据的一致性。如果事务发生异常或回滚,可以使用 undo log 中的信息将数据恢复到事务开始前的状态,以保证事务的原子性。

总之,undo log 通过保存数据的原始值来保证事务的原子性,可以使得数据修改操作能够撤销和回滚,并确保数据的一致性。

(三)redo log 持久性分析
redo log 是 InnoDB 存储引擎实现事务持久性的重要机制之一。在事务提交时,InnoDB 会将事务所做的修改操作记录在 redo log 中,并确保其持久化到磁盘上,从而保证数据的持久性。

具体来说,InnoDB 使用 WAL 技术(Write-Ahead Logging)来实现 redo log 的持久化。WAL 技术的基本思想是先将修改操作记录到 redo log 中,再将数据写入磁盘中。这样可以确保在出现宕机等异常情况时,可以通过 redo log 中的信息将数据恢复到事务执行前的状态,从而保证数据的一致性和持久性。

在 InnoDB 中,redo log 是以固定大小的文件形式存在的。当 redo log 文件被写满后,InnoDB 会自动创建新的 redo log 文件,并将新的修改操作记录在新的文件中。旧的 redo log 文件可以在不影响数据一致性的情况下被删除,从而实现 redo log 的循环利用。

为了确保 redo log 的持久化,InnoDB 在写入 redo log 时会采用一些优化技术,例如 write-ahead logging 和 group commit。write-ahead logging 是指在修改数据之前,先将修改操作记录在 redo log 中,再将数据写入磁盘中。这样可以确保即使出现宕机等异常情况,也可以通过 redo log 中的信息将数据恢复到事务执行前的状态。而 group commit 是指将多个事务的提交操作合并到一起,一起写入 redo log 中,从而减少写入磁盘的次数,提高写入性能。

综上所述,InnoDB 通过 WAL 技术实现 redo log 的持久化,并采用 write-ahead logging 和 group commit 等优化技术来提高写入性能。这些机制共同保证了 MySQL 数据库的事务持久性,从而保证了数据的一致性和可靠性。

(四)多版本并发控制(MVCC)隔离性分析
MVCC(Multi-Version Concurrency Control)是 InnoDB 存储引擎用来实现事务隔离的一种技术。MVCC 技术通过为每个事务保存一个可见的数据版本,来实现在并发访问的情况下保证事务的隔离性。MVCC 主要涉及以下两个方面:

版本号

在 MVCC 中,每一行数据都会有多个版本号,每个版本号对应着一个事务,表示该版本是由该事务所修改的。事务在进行修改时,会为该行数据生成一个新的版本,该版本号比当前最大的版本号大1。而查询操作只能读取版本号小于等于当前事务的版本号的数据。

事务版本链

每个事务都有一个版本链,版本链是由该事务创建的所有版本所组成的链表。在该链表上,每个版本都指向前一个版本,最后一个版本指向 NULL。版本链的作用是,当事务需要回滚时,可以沿着版本链将数据恢复到事务开始的状态。

通过使用版本号和事务版本链,MVCC 实现了 InnoDB 存储引擎的多版本并发控制,同时也保证了事务的隔离性。在执行查询操作时,根据当前事务的隔离级别,InnoDB 存储引擎会选择可见的数据版本。在可重复读的隔离级别下,InnoDB 存储引擎会将当前事务的版本号作为可见的最大版本号,因此当前事务只能读取该版本号之前的数据版本,避免了脏读和不可重复读等问题。


MVCC只在RR和RC隔离级别下生效,不同的是RR级别下在事务第一个select语句开始的时候生成快照读视图,RC级别下每次select都会生成新的读视图。

需要注意的是,MVCC 技术虽然可以有效地提高并发性,但同时也会带来一些问题,如版本链过长可能导致性能问题,同时需要占用更多的存储空间来保存多个版本。因此,在使用 MVCC 技术时,需要权衡其带来的利弊,合理地设置事务隔离级别和存储空间等参数。

(五)MySQL的锁机制一致性与隔离性性分析
锁机制主要是为了保证并发事务的一致性和隔离性。在并发事务中,多个事务可能同时操作相同的数据,如果不进行锁定,就会产生数据不一致的问题。例如,两个事务同时对同一行数据进行修改,如果没有锁机制,可能会导致数据被覆盖,从而造成数据的不一致。

通过使用锁机制,可以保证每个事务在修改数据时,都能够独占相应的资源,防止其他事务对数据的并发操作,从而保证了事务的一致性。同时,锁机制也可以通过设置不同的隔离级别来保证事务之间的隔离性,避免不同事务之间的互相干扰和影响。

因此,锁机制既保证了并发事务的一致性,也保证了事务之间的隔离性。具体原理可以概括为:在事务修改数据之前,需要先获得相应的锁,获得锁之后,事务才可以修改数据,并且在整个事务期间,这部分数据都是锁定的,其他事务如果要修改数据,必须等待当前事务提交或回滚后释放锁。

行锁与表锁
锁按照粒度可以分为行锁和表锁。表锁会锁定整张表,而行锁则只锁定需要操作的数据,显然行锁具有更好的并发性能。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源。

InnoDB同时支持表锁和行锁,出于性能考虑,绝大多数情况下使用的都是行锁。InnoDB实现了两种标准行级锁:

共享锁(S Lock):允许事务读一行数据。在select语句后面加上lock in share mode可以显式获取共享锁

排他锁(X Lock):允许事务删除或更新一行数据。update、delete和insert语句会自动给涉及数据集加排他锁,select语句需要在语句后加上for update显式加排他锁

#排他锁
SELECT * FROM table_name WHERE ... FOR UPDATE;
#共享锁
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;

意向锁
意向锁是一种特殊的表级锁,它是为了协调行级锁和表级锁而引入的。在进行行级锁定之前,InnoDB 存储引擎会先使用意向锁来协调并通知其它事务该行的锁定情况,从而提高并发性能。

意向锁分为两种类型:

意向共享锁(Intention Shared Lock,IS锁):表示一个事务想要在某个数据行上加共享锁,此时会先设置该表的 IS 锁。当一个事务想要在某个数据行上加行级共享锁时,需要检查该表的 IS 锁是否存在,如果存在,则说明有其它事务想要在该表上加行级共享锁,此时需要等待其它事务释放 IS 锁后再进行加锁操作。
意向排他锁(Intention Exclusive Lock,IX锁):表示一个事务想要在某个数据行上加排他锁,此时会先设置该表的 IX 锁。当一个事务想要在某个数据行上加行级排他锁时,需要检查该表的 IX 锁是否存在,如果存在,则说明有其它事务想要在该表上加行级共享锁或行级排他锁,此时需要等待其它事务释放 IX 锁后再进行加锁操作。
使用意向锁的主要目的是减少锁冲突,提高并发性能,同时保证数据的一致性。如果没有意向锁的协调机制,可能会导致不同事务之间的锁定产生冲突,从而降低并发性能。

行锁算法(记录锁+间隙锁+下一键锁)
在行锁中,有三种行锁算法:Record Lock、Gap Lock和Next-Key Lock。下面对这三种锁进行详细分析:

Record Lock(记录锁):Record Lock是在行上设置的锁,用于保证在事务中不会有其他事务对同一行进行修改。在事务中对某一行进行修改时,会对该行加上记录锁,其他事务需要对该行进行修改时,必须等待该记录锁被释放。
Gap Lock(间隙锁):Gap Lock是在索引记录之间设置的锁,用于防止其他事务在这些索引记录之间插入新的索引记录。在事务中对索引进行修改时,会对索引记录之间的间隙加上间隙锁,其他事务需要在这些间隙之间插入新的索引记录时,必须等待间隙锁被释放。
Next-Key Lock(下一键锁):Next-Key Lock是Record Lock和Gap Lock的结合体,同时锁住了索引记录和索引记录之间的间隙。在事务中对索引进行修改时,会对索引记录及其间隙加上下一键锁,其他事务需要对这些索引记录及其间隙进行修改时,必须等待下一键锁被释放。
在上述三种锁中,Record Lock用于保证行的并发访问,Gap Lock用于保证索引记录之间的并发访问,Next-Key Lock则是前两种锁的结合体,用于同时保证行和索引记录之间的并发访问。

需要注意的是,Next-Key Lock并不仅仅是Record Lock和Gap Lock的简单叠加,而是在两种锁的基础上增加了额外的约束条件。例如,Next-Key Lock会锁定当前索引记录及其间隙,并要求下一个索引记录不能被锁定。这种锁的机制可以有效地避免死锁的发生,同时保证数据的一致性和完整性。


http://www.kler.cn/news/361613.html

相关文章:

  • 【RL Latest Tech】安全强化学习(Safe RL):理论、方法与应用
  • CMakeLists.txt 编写规则
  • 苍穹外卖学习笔记(三十二最终篇)
  • 【Kuberntes】k8s权限管理
  • SQL Injection | MySQL 手工注入全流程
  • Python|基于Kimi大模型,实现上传文档并进行“多轮”对话(7)
  • 快速修改DBeaver快捷键设置
  • Jupyter Notebook中 Save and Export Notebook As不显示选项
  • C++ [项目] 飞机大战
  • word删除空白页 | 亲测有效
  • 专利交易:创新成果的桥梁
  • 数据结构实验:实现二叉树的各种基本运算的算法
  • 使用python绘制图表
  • node和npm版本冲突
  • Java-如果你的目标是从一个包含多个 Map 的 List 中统计所有 Map 中特定键(例如 “name“)的值,并将这些值组成一个新的 List
  • “网络协议入门:HTTP通信的四大组成部分“
  • 4步教你绘制流程图,轻松提高工作效率!
  • python+大数据+基于spark的短视频推荐系统【内含源码+文档+部署教程】
  • ResourceManager 与 JobManager与 TaskManager 三者的协作关系
  • Swift用于将String拆分为数组的components与split的区别
  • 算法专题八: 链表
  • 9. JSON RPC 服务
  • Java最全面试题->Java基础面试题->JavaWeb面试题->Git/SVN面试题
  • Spring Boot助力:构建响应式论坛网站
  • python 结构作业
  • Maven项目管理工具-初始+环境配置