MySQL高级讲座篇之：ACID的哲学思考：在MySQL中如何保证数据的一致性、持久性与隔离性。

admin
Sat, 16 Aug 2025 05:13:39 +0000
Mysql, acid, mysql, 保证数据

各位观众老爷，大家好！我是今天的主讲人，江湖人称“数据界的段子手”。今天咱们不聊风花雪月，就来聊聊数据库里那些不得不说的故事，特别是MySQL中，如何保证咱们辛辛苦苦攒下的数据，既不会丢，也不会乱，还能让大家伙儿井然有序地访问，也就是ACID的哲学思考。 咱们先热热身，来个段子： 话说有一天，张三去银行存钱，存了1000块，结果银行系统突然崩溃了。张三心想：完了，我的钱是不是没了？幸好银行用了ACID，最终张三的钱稳稳当当地躺在了账户里。 这虽然是个段子，但却生动地说明了ACID的重要性。那么，ACID到底是个啥玩意儿呢？别急，咱们慢慢道来。 ACID：数据库的四大护法 ACID，是数据库事务必须具备的四个特性，分别是： 原子性（Atomicity）： 要么全部成功，要么全部失败。 一致性（Consistency）： 事务执行前后，数据必须保持一致的状态。 隔离性（Isolation）： 多个事务并发执行时，互相不干扰。 持久性（Durability）： 事务一旦提交，数据就永久保存，雷打不动。 这四大护法，守护着咱们的数据安全，缺一不可。接下来，咱们逐个击破，看看MySQL是如何实现 …

继续阅读“MySQL高级讲座篇之：ACID的哲学思考：在MySQL中如何保证数据的一致性、持久性与隔离性。”

The post MySQL高级讲座篇之：ACID的哲学思考：在MySQL中如何保证数据的一致性、持久性与隔离性。 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

各位观众老爷，大家好！我是今天的主讲人，江湖人称“数据界的段子手”。今天咱们不聊风花雪月，就来聊聊数据库里那些不得不说的故事，特别是MySQL中，如何保证咱们辛辛苦苦攒下的数据，既不会丢，也不会乱，还能让大家伙儿井然有序地访问，也就是ACID的哲学思考。

咱们先热热身，来个段子：

话说有一天，张三去银行存钱，存了1000块，结果银行系统突然崩溃了。张三心想：完了，我的钱是不是没了？幸好银行用了ACID，最终张三的钱稳稳当当地躺在了账户里。

这虽然是个段子，但却生动地说明了ACID的重要性。那么，ACID到底是个啥玩意儿呢？别急，咱们慢慢道来。

ACID：数据库的四大护法

ACID，是数据库事务必须具备的四个特性，分别是：

原子性（Atomicity）： 要么全部成功，要么全部失败。

一致性（Consistency）： 事务执行前后，数据必须保持一致的状态。

隔离性（Isolation）： 多个事务并发执行时，互相不干扰。

持久性（Durability）： 事务一旦提交，数据就永久保存，雷打不动。

这四大护法，守护着咱们的数据安全，缺一不可。接下来，咱们逐个击破，看看MySQL是如何实现它们的。

一、原子性（Atomicity）：要么一起嗨，要么一起凉

原子性，说白了就是把一个事务看作一个不可分割的整体。这个整体里的所有操作，要么全部成功，要么全部失败，绝不允许出现“一半成功，一半失败”的尴尬局面。

MySQL如何实现原子性？

MySQL主要通过 Undo Log 来实现原子性。Undo Log记录了事务中每个操作的反向操作。如果事务执行过程中出现错误，MySQL就可以利用Undo Log来回滚事务，将数据恢复到事务开始之前的状态。

举个例子：

-- 开启事务
START TRANSACTION;

-- 张三给李四转账100块
UPDATE accounts SET balance = balance - 100 WHERE name = '张三';
UPDATE accounts SET balance = balance + 100 WHERE name = '李四';

-- 假设这里发生了错误（例如：李四的账户不存在）

-- 回滚事务（MySQL会自动使用Undo Log）
ROLLBACK;

在这个例子中，如果第二个UPDATE语句执行失败，MySQL会自动使用Undo Log来撤销第一个UPDATE语句的操作，保证张三的账户余额不会减少。

Undo Log的简单原理:

操作类型 | Undo Log记录内容
INSERT | 被插入记录的主键，以及所有列的值。回滚时删除该记录。
UPDATE | 被更新记录的主键，以及更新前所有列的值。回滚时恢复这些值。
DELETE | 被删除记录的主键，以及所有列的值。回滚时重新插入该记录。

二、一致性（Consistency）：数据必须始终保持正确

一致性，是ACID中最核心的特性。它保证了事务执行前后，数据必须满足预定义的规则和约束。这些规则和约束包括：

数据类型约束： 例如，年龄必须是整数，电话号码必须是字符串。

唯一性约束： 例如，用户名必须唯一。

外键约束： 例如，订单表中的用户ID必须存在于用户表中。

自定义约束： 例如，银行账户余额不能为负数。

MySQL如何实现一致性？

MySQL通过以下手段来保证一致性：

约束（Constraints）： 通过定义各种约束来保证数据的有效性。

触发器（Triggers）： 在特定事件发生时自动执行的存储过程，可以用来检查和修改数据。

应用程序逻辑： 在应用程序代码中编写逻辑来验证数据的正确性。

约束的例子：

-- 创建用户表，并定义唯一性约束和非空约束
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL,
    age INT CHECK (age >= 0) -- 年龄必须大于等于0
);

在这个例子中，UNIQUE 约束保证了用户名不能重复，NOT NULL 约束保证了用户名和邮箱不能为空，CHECK 约束保证了年龄必须大于等于0。

触发器的例子：

-- 创建触发器，在插入新订单时，检查订单金额是否大于0
CREATE TRIGGER check_order_amount
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
    IF NEW.amount <= 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = '订单金额必须大于0';
    END IF;
END;

在这个例子中，触发器会在每次插入新订单之前检查订单金额是否大于0，如果小于等于0，则会抛出一个错误。

三、隔离性（Isolation）：互不打扰，各玩各的

隔离性，是指多个事务并发执行时，互相不干扰，每个事务都感觉自己在独立地访问数据库。

并发事务可能遇到的问题：

脏读（Dirty Read）： 一个事务读取了另一个事务未提交的数据。

不可重复读（Non-repeatable Read）： 一个事务多次读取同一行数据，结果每次读取到的数据都不一样。

幻读（Phantom Read）： 一个事务多次执行同一条查询语句，结果每次查询到的记录数量都不一样。

MySQL如何实现隔离性？

MySQL通过 锁机制 和 多版本并发控制（MVCC） 来实现隔离性。

1. 锁机制：

MySQL提供了多种锁，包括：

共享锁（Shared Lock）： 多个事务可以同时持有同一个共享锁，用于读取数据。

排他锁（Exclusive Lock）： 只有一个事务可以持有同一个排他锁，用于修改数据。

当一个事务要修改数据时，它会先获取该数据的排他锁。其他事务如果想读取或修改该数据，必须等待该事务释放锁。

2. 多版本并发控制（MVCC）：

MVCC是一种乐观锁的实现方式。它为每一行数据维护多个版本，每个版本都有一个时间戳。当一个事务要读取数据时，它会读取当前时间戳之前的最新版本。当一个事务要修改数据时，它会创建一个新的版本，并将其时间戳设置为当前时间戳。

MVCC可以避免读取操作阻塞写入操作，提高并发性能。

MySQL的四种隔离级别：

MySQL支持四种隔离级别，分别是：

隔离级别 | 脏读 | 不可重复读 | 幻读
READ UNCOMMITTED | 是 | 是 | 是
READ COMMITTED | 否 | 是 | 是
REPEATABLE READ | 否 | 否 | 是
SERIALIZABLE | 否 | 否 | 否

READ UNCOMMITTED： 允许读取未提交的数据，隔离性最差，性能最高。

READ COMMITTED： 只允许读取已提交的数据，可以防止脏读，但无法防止不可重复读和幻读。

REPEATABLE READ： 保证在同一个事务中多次读取同一行数据的结果是一样的，可以防止脏读和不可重复读，但无法防止幻读。MySQL的默认隔离级别。

SERIALIZABLE： 强制事务串行执行，隔离性最好，但性能最低。

如何设置隔离级别？

-- 设置当前会话的隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 设置全局的隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

四、持久性（Durability）：落袋为安，永不反悔

持久性，是指事务一旦提交，对数据库的修改就是永久性的，即使数据库发生故障，数据也不会丢失。

MySQL如何实现持久性？

MySQL主要通过 Redo Log 来实现持久性。Redo Log记录了事务中每个操作对数据的修改。当数据库发生故障时，MySQL可以利用Redo Log来重放事务，将数据恢复到事务提交之后的状态。

Redo Log的简单原理:

Redo Log记录的是物理修改，也就是对哪个数据页的哪个位置做了什么修改。相比Undo Log记录逻辑操作，Redo Log的写入效率更高，因为只需要记录修改的内容，而不需要记录如何撤销修改。

Redo Log的写入过程：

1. 事务执行过程中，会将对数据的修改记录写入Redo Log Buffer。

2. 当事务提交时，或者Redo Log Buffer满了，会将Redo Log Buffer中的内容刷入Redo Log File。

3. MySQL会定期将Redo Log File中的内容刷入磁盘上的数据文件。

Write-Ahead Logging (WAL)策略：

MySQL使用Write-Ahead Logging (WAL)策略来保证持久性。WAL策略要求必须先将Redo Log写入磁盘，才能将数据修改写入磁盘。这样，即使数据库发生故障，也可以通过Redo Log来恢复数据。

总结：ACID的完美组合

ACID四个特性相互依赖，共同保证了数据库的可靠性和一致性。

原子性 保证了事务的完整性，要么全部成功，要么全部失败。

一致性 保证了数据的正确性，事务执行前后数据必须满足预定义的规则和约束。

隔离性 保证了并发事务的互不干扰，每个事务都感觉自己在独立地访问数据库。

持久性 保证了数据的永久保存，事务一旦提交，数据就不会丢失。

ACID的取舍：

在实际应用中，为了提高性能，有时候需要对ACID进行一定的取舍。例如，可以降低隔离级别，允许一定程度的脏读、不可重复读或幻读。但是，必须权衡利弊，确保数据的可靠性和一致性不会受到严重影响。

一些额外的思考：

BASE理论： 与ACID相对的是BASE理论，BASE是Basically Available, Soft state, Eventually consistent的缩写。BASE理论强调可用性和最终一致性，适用于高并发、高可用的分布式系统。

CAP理论： CAP理论指出，在一个分布式系统中，Consistency（一致性）、Availability（可用性）、Partition tolerance（分区容错性）这三个特性最多只能同时满足两个。

代码示例：一个完整的转账事务

-- 开启事务
START TRANSACTION;

-- 设置隔离级别（这里设置为REPEATABLE READ）
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 查询张三的余额
SELECT balance FROM accounts WHERE name = '张三' FOR UPDATE; -- 加排他锁，防止其他事务修改张三的余额

-- 查询李四的余额
SELECT balance FROM accounts WHERE name = '李四' FOR UPDATE; -- 加排他锁，防止其他事务修改李四的余额

-- 张三给李四转账100块
UPDATE accounts SET balance = balance - 100 WHERE name = '张三';
UPDATE accounts SET balance = balance + 100 WHERE name = '李四';

-- 提交事务
COMMIT;

在这个例子中，我们使用了FOR UPDATE语句来获取排他锁，防止其他事务在转账过程中修改张三和李四的余额，保证了事务的隔离性。同时，MySQL会使用Undo Log和Redo Log来保证原子性和持久性。

总结：

ACID是数据库的基石，是保证数据可靠性和一致性的重要手段。理解ACID的原理，可以帮助我们更好地设计和使用数据库，避免数据丢失和错误。

今天的讲座就到这里，希望大家有所收获。记住，数据无价，ACID保驾！ 咱们下期再见！