
目录一、MySQL事务简单介绍二、事务特性ACID介绍一原子性Atomicity二一致性Consistency三隔离性Isolation四持久性Durability三、事务隔离级别四、MySQL事务实现原理一事务原理总述二undo log 原子性分析三redo log 持久性分析四多版本并发控制MVCC隔离性分析五MySQL的锁机制一致性与隔离性性分析行锁与表锁意向锁扩展意向锁、共享锁和排他锁的兼容性行锁算法记录锁间隙锁下一键锁六死锁问题分析简单锁举例场景典型形成环路的死锁例子扩展避免死锁技巧五、总结参考文章链接干货分享感谢您的阅读在现代数据库管理系统中事务是保证数据一致性和可靠性的核心机制之一。尤其在多用户并发操作的环境下如何确保每个操作都能按预期执行避免数据损坏或错误成为了数据库设计和应用中的重要挑战。MySQL作为广泛使用的关系型数据库管理系统其事务机制的实现深刻影响着数据处理的效率和安全性。本篇文章将深入探讨MySQL事务的基本概念、实现原理以及其在高并发场景中的应用。我们将详细解析MySQL事务如何遵循ACID原子性、一致性、隔离性、持久性原则如何通过不同的隔离级别来平衡性能和数据一致性需求。此外我们还将重点介绍事务的底层实现原理帮助读者从源码层面理解MySQL是如何管理事务以及如何保证事务的正确性和高效性。通过这篇文章你将不仅了解MySQL事务的基本操作和使用方法还能深入理解其背后的实现原理为你的数据库开发与优化提供有力的理论支持。一、MySQL事务简单介绍MySQL事务是指一组操作它们被看作一个单独的工作单元要么全部成功要么全部失败回滚。在MySQL中事务可以确保数据的一致性和完整性。事务通常由四个关键词来描述BEGIN 或 START TRANSACTION标志着事务的开始。COMMIT表示事务完成并把所有的修改持久化到数据库。ROLLBACK表示事务的失败并且撤销所有对数据库的修改。SAVEPOINT可以设置事务的一个保存点可以回滚到此处。在MySQL中只有使用了InnoDB存储引擎的表才支持事务。当执行一系列的SQL语句时如果其中有一个SQL语句执行失败则所有SQL语句都会回滚也就是说之前的所有SQL操作都被撤销数据库回到之前的状态。而只有当所有SQL语句都执行成功后它们才会被提交到数据库中这就保证了数据的一致性。事务在开发中常用于保证数据的完整性和一致性例如在进行银行转账时需要保证从一个账户扣除的金额一定会被转入到另一个账户中如果出现了其中一个账户扣除了金额而另一个账户没有收到对应的金额的情况那么这就是一种数据的不一致性。在这种情况下使用事务可以保证这个问题不会发生因为要么所有的操作都成功要么都失败。二、事务特性ACID介绍一原子性Atomicity事务中的所有操作要么全部成功要么全部失败回滚。如果有一个操作失败则整个事务都应该回滚到最初状态。例如假设我们有一个银行转账系统。当我们从一个账户转账到另一个账户时需要确保资金的安全和正确性。如果转账过程中任何一个步骤失败例如金额不足或接收方账户不存在则必须回滚到最初状态确保事务的原子性。二一致性Consistency在事务执行过程中数据库必须始终保持一致状态。在事务执行的任何时刻数据库必须满足一组事务的约束条件。例如假设我们有一个订单系统。当用户下订单时订单总金额必须小于用户账户的余额。如果订单总金额大于用户账户的余额则必须回滚事务以保持一致性。三隔离性Isolation事务应该在相互隔离的环境中执行以避免并发执行时可能出现的问题。每个事务都应该以一种完全独立的方式执行不受其他事务的影响。例如如果两个用户在同一时间购买同一件商品系统必须确保两个用户看到的是正确的库存量并且不会出现两个用户都买到同一件商品的情况。四持久性Durability一旦事务成功提交其结果就应该持久保存在数据库中即使系统崩溃或重新启动数据也应该仍然存在。例如假设我们有一个电子邮件系统。当用户发送电子邮件时该邮件必须被保存在数据库中即使系统在发送电子邮件后崩溃也必须确保该邮件在系统恢复后仍然存在。需要注意的是不同的数据库管理系统对事务的实现方式可能会有所不同因此在使用事务时需要根据具体的数据库管理系统和应用场景来选择适合的实现方式。三、事务隔离级别在没有隔离级别的情况下可能会发生以下情况脏读Dirty Read一个事务读取了另一个事务还未提交的数据如果这个事务回滚那么读到的数据就是无效的这种情况称为脏读。不可重复读Non-repeatable Read一个事务在执行过程中多次读取同一数据由于其他事务对该数据进行了修改因此这些读取操作得到的结果可能不同这种情况称为不可重复读。幻读Phantom Read一个事务按照相同的查询条件两次查询但是得到的结果集却不同。这是因为其他事务对该表进行了新增或删除操作导致当前事务查询到的结果集不一致这种情况称为幻读。这些情况都是由于多个事务之间的数据相互干扰导致的而隔离级别就是用来解决这些问题的。事务的隔离级别规定了在一个事务内的修改哪些在事务内和事务间可见哪些不可见。SQL标准定义了四个隔离级别一般而言隔离级别越高安全性越高但系统开销更大并发性能也越差。隔离级别含义脏读不可重复读幻读读未提交Read Uncommitted一个事务执行的操作即使还未提交也能被其他事务看到存在存在存在读已提交Read Committed一个事务提交之后其他事务才能看到该事务的修改不存在存在存在可重复读Repeatable Read同一个事务内多次读取的结果一致不存在不存在存在可串行化Serializable强制事务串行按顺序执行不存在不存在不存在通过如下SQL命令可以查看和修改MySQL的事务隔离级别-- 查看全局事务隔离级别 select global.tx_isolation -- 查看当前会话事务隔离级别 select tx_isolation -- 修改全局事务隔离级别 set global transaction isolation level repeatable read -- 修改当前会话事务隔离级别 set session transaction isolation level repeatable read在实际应用中读未提交级别在并发时会导致很多问题性能相对于其他隔离级别提高也有限可串行化级别强制事务串行并发效率很低只适合于对数据一致性要求极高的场景这两个隔离级别都很少使用。因此在大多数数据库系统中默认的隔离级别是RC读已提交或RR可重复读。MySQL的InnoDB默认隔离级别是RR可重复读但与标准SQL不同的是InnoDB在RR可重复读隔离级别下使用Next-Key锁避免了幻读问题。也就是说InnoDB在RR隔离级别下已经能完全保证事务隔离性要求即达到了SQL标准的Serializable隔离级别。四、MySQL事务实现原理一事务原理总述MySQL 事务是基于 InnoDB 存储引擎实现的。MySQL 的事务原理主要包括以下几个方面redo logInnoDB 在执行事务时会将事务的修改操作记录在 redo log 中以保证事务的持久性。redo log 记录了每个事务对数据所做的修改包括修改的行、列和修改前后的值等信息。当事务提交时会将 redo log 写入到磁盘中以保证数据的持久性。undo logInnoDB 在执行事务时会将事务的修改操作记录在 undo log 中以支持事务的回滚和 MVCC 功能。undo log 记录了每个事务对数据所做的修改包括修改的行、列和修改前的值等信息。当事务需要回滚时会使用 undo log 中的信息将数据恢复到事务执行前的状态。MVCCInnoDB 实现了多版本并发控制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隔离性分析MVCCMulti-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 LockIS锁表示一个事务想要在某个数据行上加共享锁此时会先设置该表的 IS 锁。当一个事务想要在某个数据行上加行级共享锁时需要检查该表的 IS 锁是否存在如果存在则说明有其它事务想要在该表上加行级共享锁此时需要等待其它事务释放 IS 锁后再进行加锁操作。意向排他锁Intention Exclusive LockIX锁表示一个事务想要在某个数据行上加排他锁此时会先设置该表的 IX 锁。当一个事务想要在某个数据行上加行级排他锁时需要检查该表的 IX 锁是否存在如果存在则说明有其它事务想要在该表上加行级共享锁或行级排他锁此时需要等待其它事务释放 IX 锁后再进行加锁操作。使用意向锁的主要目的是减少锁冲突提高并发性能同时保证数据的一致性。如果没有意向锁的协调机制可能会导致不同事务之间的锁定产生冲突从而降低并发性能。扩展意向锁、共享锁和排他锁的兼容性ISIXSXIS兼容兼容兼容不兼容IX兼容兼容不兼容不兼容S兼容不兼容兼容不兼容X不兼容不兼容不兼容不兼容行锁算法记录锁间隙锁下一键锁在行锁中有三种行锁算法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会锁定当前索引记录及其间隙并要求下一个索引记录不能被锁定。这种锁的机制可以有效地避免死锁的发生同时保证数据的一致性和完整性。案例分析CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50), age INT );Record Lock行锁算法举例当执行一个更新操作时InnoDB 会将要更新的行加上行锁以保证其它事务不能修改这一行直到当前事务提交或回滚。如果其它事务要修改同一行必须等待该行的行锁被释放。现在执行以下两个事务事务 A BEGIN; SELECT * FROM user WHERE id1 FOR UPDATE; -- do some updates COMMIT; 事务 B BEGIN; SELECT * FROM user WHERE id1 FOR UPDATE; -- do some updates COMMIT;当事务 A 执行 SELECT * FROM user WHERE id1 FOR UPDATE; 语句时会将 id1 的行加上行锁。因此当事务 B 执行 SELECT * FROM user WHERE id1 FOR UPDATE; 时会被阻塞直到事务 A 释放行锁。Gap Lock行锁算法举例Gap Lock 的作用是锁定一个范围但不包括记录本身。当一个事务要向一个不存在的记录插入数据时InnoDB 会加上 Gap Lock以确保没有其它事务插入相同的记录。同样的如果其它事务要更新或删除这个范围内的记录也会被阻塞。现在执行以下两个事务事务 A BEGIN; INSERT INTO user (id, name, age) VALUES (5, Tom, 25); COMMIT; 事务 B BEGIN; SELECT * FROM user WHERE id 4 AND id 6 FOR UPDATE; -- do some updates COMMIT;当事务 A 执行 INSERT INTO user (id, name, age) VALUES (5, Tom, 25); 语句时会加上 Gap Lock锁定 id 4 AND id 6 这个范围。因此当事务 B 执行 SELECT * FROM user WHERE id 4 AND id 6 FOR UPDATE; 时会被阻塞直到事务 A 释放 Gap Lock。Next-Key Lock行锁算法举例Next-Key Lock 不仅锁定范围还锁定范围内的记录以保证记录在范围内的行被锁定。Next-Key Lock 由两部分组成一部分是 Gap Lock一部分是 Record Lock。下面给出 Next-Key Lock 的三种典型情况当事务 A 执行 INSERT INTO user (id, name, age) VALUES (5, Tom, 25); 语句时会加上 Next-Key Lock锁定 id 5 这一行。因此当事务 B 执行 SELECT * FROM user WHERE id 5 FOR UPDATE; 时会被阻塞直到事务 A 释放 Next-Key Lock。当事务 A 执行 DELETE FROM user WHERE id 5; 语句时会加上 Next-Key Lock锁定 id 5 这一行。因此当事务 B 执行 SELECT * FROM user WHERE id 5 FOR UPDATE; 时会被阻塞直到事务 A 释放 Next-Key Lock。当事务 A 执行 UPDATE user SET age 30 WHERE id 5; 语句时会加上 Next-Key Lock锁定 id 5 这一行。因此当事务 B 执行 SELECT * FROM user WHERE id 5 FOR UPDATE; 时会被阻塞直到事务 A 释放 Next-Key Lock。Next-Key Lock 可以保证不会出现幻读的情况因为 Next-Key Lock 不仅锁定了范围还锁定了范围内的记录。而幻读是由于范围内有新插入的行导致的Next-Key Lock 可以锁定这些新插入的行从而避免了幻读的发生。六死锁问题分析既然InnoDB对记录操作时会加锁不可避免会出现死锁的问题。如果两个事务在执行过程中都持有对方需要的锁并且在等待对方释放锁此时就发生了死锁。简单锁举例场景假设我们有一张表user(id, name, age)id是主键name是普通索引。索引数据如下场景一delete from user where id3 走id主键索引会直接锁主键索引上id为3的记录场景二delete from user where name卢自清 走name二级索引会先锁住二级索引然后再去锁聚簇索引上对应主键的记录场景三delete from user where age20 不走索引全表扫描会对所有记录加锁可以看到查询条件的不同加锁的结果也不一样。而死锁一般是事务相互等待对方的锁最后形成环路造成的。典型形成环路的死锁例子操作不同表的相同记录事务A事务Bbegin;delete from table1 where id2;begin;update table2 set msgaaa where id1;update table2 set msgaaa where id1;delete from table1 where id2;这个比较好理解事务A持有表table1的id2记录行锁等待表table2的id1的记录行锁事务B持有表table2的id1记录行锁等待表table1的id2记录行锁两者互相等待出现死锁操作同一张表的相同记录事务A事务Bbegin;delete from table1 where id2;begin;delete from table1 where id1;delete from table1 where id1;delete from table1 where id2;这个比较常见事务在批量更新的时候如果一个事务更新的顺序是[1,2]另一个事务更新的顺序是[2,1]就可能出现死锁不同索引造成锁冲突事务A事务Bbegin;update user set name张清风 where name卢自清;begin;delete from user where id2;这个就很隐晦了事务A在执行时除了在二级索引加锁外还会在主键索引上加锁在主键索引上加锁的顺序是[2,5]事务B执行时只在主键索引上加锁加锁顺序是[2]。[2]存在环路有发生死锁的可能。gap锁冲突事务A事务Bbegin;update user set name张清风 where name卢自清;begin;update user set name张清风 where name王澄泓;insert into user values(null,林可佳,19);insert into user values(null,闫澜飜,28);事务A和事务B都持有gap锁插入数据时都要等待对方的gap锁释放发生死锁。扩展避免死锁技巧由于死锁是个偶发性的问题对线上造成的影响也难以预料要求在业务层面采取措施避免死锁的发生下面给出了几个可以避免死锁的技巧以固定的顺序访问表和行避免循环等待大事务更容易发生死锁如果业务允许将大事务拆小。在同一个事务中尽可能做到一次锁定所需要的所有资源减少死锁概率。降低隔离级别。如果业务允许将隔离级别从RR调整为RC可以避免掉很多因为gap锁造成的死锁。为表添加合理的索引。如果不走索引将会为表的所有行都加锁增大了死锁的概率。五、总结在本文中我们深入探讨了MySQL事务的基本概念及其实现原理。事务作为数据库管理系统中的一个关键组成部分能够确保在并发操作中维护数据的一致性与完整性。我们详细介绍了事务的四大基本特性——ACID原则以及MySQL如何通过不同的隔离级别来平衡性能与一致性满足不同场景下的需求。通过分析MySQL事务的实现原理我们揭示了InnoDB存储引擎如何通过MVCC多版本并发控制、锁机制、日志文件等技术保证事务的原子性和隔离性处理并发访问时的读写冲突。此外事务的日志记录机制包括redo日志和undo日志也为我们提供了在出现故障时恢复数据的一种有效手段。在实际开发中合理的事务管理不仅能保证数据的可靠性还能在一定程度上提高系统的性能。理解事务的底层实现原理将帮助开发者在进行数据库设计和性能调优时做出更明智的决策。总之MySQL事务机制不仅是数据库操作的核心之一也是保障数据安全、提高系统并发性能的重要技术。希望本文的分析和讲解能够为读者在数据库开发和优化过程中提供帮助并为深入理解数据库底层技术奠定基础。参考文章链接阮一峰的《MySQL 教程》中的事务部分https://www.ruanyifeng.com/blog/2013/12/mysql_tutorial.htmlMySQL 官方文档中的事务部分MySQL :: MySQL 8.0 Reference Manual :: 13.3.1 START TRANSACTION, COMMIT, and ROLLBACK Statements阿里云数据库 RDS 的事务管理介绍404错误页-阿里云帮助中心《高性能 MySQL》一书中的事务部分高性能MySQL(第3版) (豆瓣)MySQL 事务详解https://www.runoob.com/mysql/mysql-transactions.htmlMySQL 事务隔离级别和锁机制详解https://www.cnblogs.com/lzrabbit/p/3734850.html深入浅出 MySQL 事务隔离级别https://www.cnblogs.com/-wenli/p/11046971.htmlInnoDB 存储引擎下的事务管理机制https://mp.weixin.qq.com/s/kZzeCLylw5zJbgRv6oOUzAMySQL 存储引擎 InnoDB 事务原理详解利用Rsync同步备份服务器数据-腾讯云开发者社区-腾讯云MySQL 事务深入分析https://www.cnblogs.com/kerrycode/p/4743812.html