数据库中的四种性质,通常称为 ACID 特性,分别是:
名称 | 含义 |
---|---|
原子性 (Atomicity) | 事务的所有操作要么全部完成,要么全部不做,不能只完成一部分。 |
一致性 (Consistency) | 事务执行前后,数据库都必须保持数据的完整性和约束规则。 |
隔离性 (Isolation) | 并发执行的事务彼此隔离,一个事务的中间状态对其他事务不可见。 |
持久性 (Durability) | 一旦事务提交,对数据库的修改是永久性的,即使系统崩溃也不会丢失。 |
ACID 特性是关系型数据库保证数据安全性和正确性的基础,每个事务都必须满足这四个条件,才能保证数据库的可靠性。
好的,我们继续来详细讲解 ACID 四大特性,尤其重点放在你感兴趣的事务问题和隔离级别上(包括脏读、不可重复读、幻读等问题)。
事务中的一系列操作要么全部成功,要么全部失败,不可能只执行一部分。
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;
如果第二条语句失败(比如用户 2 不存在),数据库会回滚第一条语句,两个账户的余额都不变。
事务开始前和结束后,数据库必须处于一致的状态(满足所有约束条件)。
转账系统中约定总余额不变:
如果执行中断或数据错乱(如 A 减了,B 没加),则违反一致性。
多个事务并发执行时,它们应该彼此隔离,一个事务看不到另一个事务的中间状态。
问题 | 描述 |
---|---|
脏读 | 事务 A 读取了事务 B 尚未提交的数据 |
不可重复读 | 事务 A 两次读取某行数据,结果不一样(B 提交了更新) |
幻读 | 事务 A 查询范围内的数据时,事务 B 插入了新行,导致 A 结果变了 |
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(Read Uncommitted) | ✅ | ✅ | ✅ |
读已提交(Read Committed) | ❌ | ✅ | ✅ |
可重复读(Repeatable Read) | ❌ | ❌ | ✅(MySQL 中也能防幻读) |
串行化(Serializable) | ❌ | ❌ | ❌ |
-- 事务A
BEGIN;
UPDATE users SET age = 100 WHERE id = 1;
-- 事务B
SELECT age FROM users WHERE id = 1; -- 看到 100(未提交)
-- 如果 A 回滚,B 读取的数据就“脏”了
-- 事务A
SELECT salary FROM emp WHERE id = 1; -- 第一次查 5000
-- 事务B
UPDATE emp SET salary = 8000 WHERE id = 1; COMMIT;
-- 事务A 再查一次
SELECT salary FROM emp WHERE id = 1; -- 第二次查 8000,值变了
-- 事务A
SELECT * FROM orders WHERE price > 1000; -- 查到10行
-- 事务B
INSERT INTO orders VALUES (id=999, price=2000); COMMIT;
-- 事务A 再次查询同条件
SELECT * FROM orders WHERE price > 1000; -- 查到11行,多了一条幻觉数据
一旦事务提交,对数据库的修改是永久性的,哪怕系统崩溃也不会丢失。