数据库事务
一、事务的基本特性 (ACID)
ACID不仅是四个特性,更是一个有机整体 :一致性(Consistency)是最终目的 ,原子性、隔离性、持久性是实现这一目的的三个核心手段。
| 特性 | 核心含义 | 经典案例解析(A向B转账100元) |
|---|---|---|
| 原子性 (Atomicity) | 事务是最小工作单元,其包含的所有操作要么全部成功,要么全部失败回滚,不允许只执行一部分。 | A账户-100和B账户+100这两个操作必须捆绑在一起。系统不会出现A的钱扣了,B的钱没到账的中间状态。 |
| 一致性 (Consistency) | 事务的最终目的 。确保数据从一个正确的状态 转换到另一个正确的状态,满足所有预定义的业务规则和约束。 | 1. 数据状态一致: 转账后,总金额不变(A+B总额从600变为600)。 2. 业务约束一致: A账户余额不能为负(若A只有90元,则转账事务应失败);主键必须保持唯一等。 |
| 隔离性 (Isolation) | 多个并发事务对同一数据进行操作时,事务之间是隔离的,不应相互干扰。这是防止并发操作导致数据不一致的关键。 | 当A向B转账的同时,如果C也向B转账,两个事务如果没有良好隔离,可能导致B的最终余额错误(如应是300,却得到200)。隔离级别定义了"干扰"的程度。 |
| 持久性 (Durability) | 事务一旦提交,其对数据的修改就是永久性的,即使系统发生故障(如宕机),数据也不会丢失。 | 转账成功后,A=400,B=200的状态被持久化保存到存储介质。系统重启后,这个结果依然存在,不会回滚到转账前的状态。 |
核心逻辑链: 通过 原子性 确保操作完整,通过 隔离性 排除并发干扰,通过 持久性 固化结果,最终共同达成 一致性 这个根本目标。
二、事务的隔离级别
隔离级别解决的核心问题是:一个事务在操作数据时,如何看待其他并发事务对同一数据的修改?
隔离级别从低到高,数据安全性递增,但并发性能递减。
| 隔离级别 | 中文名 | 解决的问题 | 允许的并发问题 | 实现关键(以MySQL为例) |
|---|---|---|---|---|
| 读未提交 (Read Uncommitted) | 脏读 | 无 | 脏读、不可重复读、幻读 | 几乎不加锁,直接读最新数据(包括未提交的)。 |
| 读已提交 (Read Committed) | 不可重复读 | 脏读 | 不可重复读、幻读 | 每次SELECT都生成新的 Read View ,只读取已提交的数据。Oracle默认级别。 |
| 可重复读 (Repeatable Read) | 幻读(部分) | 脏读、不可重复读 | 幻读(在MySQL的InnoDB中,通过间隙锁已基本解决) | 事务开始时生成一个Read View ,在整个事务期间复用,保证每次读到的数据快照一致。MySQL默认级别。 |
| 串行化 (Serializable) | - | 脏读、不可重复读、幻读 | 无(但性能最低) | 通过强制事务串行执行来实现最高隔离。 |
三、隔离级别引发的三大问题详解
通过"并发转账"或"重复查询"场景理解:
-
脏读 (Dirty Read)
-
现象: 事务A读到了事务B尚未提交的修改。
-
危害: 如果事务B最终回滚,事务A读到的就是根本不存在的"脏数据"。
-
场景: 发生在
读未提交级别。
-
-
不可重复读 (Non-repeatable Read)
-
现象: 在同一个事务A内,两次读取同一条记录,得到的值不同。
-
原因: 在两次读取之间,该记录被另一个已提交的事务B修改了。
-
场景: 发生在
读已提交级别,在可重复读级别中被解决。
-
-
幻读 (Phantom Read)
-
现象: 在同一个事务A内,两次执行相同的条件查询 ,第二次查询结果集比第一次多出(或减少)了一些行(像出现了幻觉)。
-
原因: 在两次查询之间,另一个已提交的事务B插入(或删除)了满足该查询条件的新数据。
-
注意:
幻读关注的是结果集行数的变化 (新增/删除),而不可重复读关注的是同一行数据内容的变更。 -
场景: 是
可重复读隔离级别理论上存在的问题。但MySQL的InnoDB引擎通过MVCC+间隙锁的机制,在很大程度上避免了幻读。
-
四、核心面试思路总结
-
不要死记硬背: 结合"转账"等业务场景理解ACID和隔离级别,理解其为什么存在 以及解决了什么问题。
-
理解默认级别:
-
MySQL (InnoDB): 默认
可重复读,并利用MVCC和锁机制有效防止了幻读。 -
Oracle / SQL Server: 默认
读已提交。 -
能解释为什么不同数据库默认级别不同(权衡数据一致性与并发性能)。
-
-
MVCC是理解关键:
读已提交和可重复读级别的不同行为,本质上是生成Read View(一致性视图)的时机不同。-
读已提交:每次SELECT都生成新Read View → 总能读到最新已提交数据 → 不可重复读。 -
可重复读:事务开始时生成一个Read View并复用 → 整个事务看到同一个数据快照 → 可重复读。
-
-
理论与实践结合: 知道如果当前数据库的隔离级别不满足业务需求(如:在
读已提交下需要避免不可重复读),应用层该如何做 (例如:使用SELECT ... FOR UPDATE加锁)。 -
区分概念: 清晰区分脏读、不可重复读、幻读 这三种现象,以及它们与丢失更新等问题的区别。
最终答案的层次: 从ACID的定义出发,阐述其内在联系,再过渡到为实现隔离性而设立的不同级别,用场景解释各级别的问题,并提及底层实现机制(如MVCC),展现出对事务全面、深入的理解。
