数据库事务
数据库事务(Transaction)是数据库操作的最小逻辑工作单元,它将一组数据库操作(增删改查)封装成一个不可分割的整体 —— 要么这组操作全部执行成功并持久化,要么全部执行失败并回滚到初始状态。其核心价值是保证数据的一致性和可靠性,尤其在并发场景、金融交易(如转账)等关键业务中不可或缺。
文章目录
一、事务的四大特性(ACID)
1. 原子性(Atomicity)
事务是一个不可分割的原子操作,就像 “原子不可再分” 一样,事务中的所有操作要么全部完成,要么全部不完成(失败后回滚),不存在中间状态。
举例:转账业务(A 账户扣 100 元,B 账户加 100 元)。如果 A 扣钱后,B 加钱失败,那么整个事务回滚,A 的钱会恢复,不会出现 “钱凭空消失” 的情况。
2. 一致性(Consistency)
事务执行前后,数据库的数据完整性约束(如主键唯一、外键关联、金额总和不变) 保持不变,数据从一个合法状态转换为另一个合法状态。
举例:转账前 A+B 的总金额是 2000 元,转账后 A+B 的总金额依然是 2000 元;如果转账导致某账户余额为负(违反完整性约束),事务会直接失败并回滚。
3. 隔离性(Isolation)
多个事务并发执行时,它们之间是相互隔离的,一个事务的执行不能被其他事务干扰。数据库通过隔离级别来控制隔离程度(隔离性越强,并发性能越差)。
举例:事务 A 正在读取某个账户的余额,事务 B 同时修改该余额,隔离性会保证事务 A 要么读到修改前的余额,要么读到修改后的余额,不会读到 “中间值”。
4. 持久性(Durability)
一个事务一旦提交(commit),其修改会被永久保存到数据库中,即使后续发生数据库崩溃、服务器宕机等故障,数据也不会丢失(底层依赖日志如 redo log 实现)。
举例:转账事务提交后,A 账户少 100、B 账户多 100 的结果会被永久保存,即使数据库重启,数据依然生效。
二、事务的并发问题(隔离性的反面)
当多个事务并发执行时,如果没有足够的隔离性,会出现以下问题(面试常考 “有哪些并发问题 + 如何解决”):
1. 脏读(Dirty Read)
一个事务读取到了另一个事务尚未提交的修改数据。
场景:事务 B 修改了账户余额为 500 元(未提交),事务 A 读取到这个 500 元,随后事务 B 回滚,事务 A 读到的就是 “脏数据”。
2. 不可重复读(Non-repeatable Read)
一个事务内多次读取同一数据,结果却不一致(因为其他事务提交了修改 / 删除操作)。
场景:事务 A 第一次读账户余额是 1000 元,事务 B 修改余额为 800 元并提交,事务 A 再次读该余额变成 800 元,前后结果不一致。
3. 幻读(Phantom Read)
一个事务内多次执行同一查询(如范围查询),结果集的行数不一致(因为其他事务提交了插入操作)。
场景:事务 A 查询 “余额> 500 的账户有 3 个”,事务 B 插入一个余额 600 的账户并提交,事务 A 再次查询时变成 4 个,像出现了 “幻觉”。
三、事务的隔离级别
事务的隔离级别是为了解决多个事务并发执行时的干扰问题(脏读、不可重复读、幻读),SQL 标准定义了4 个核心隔离级别,不同数据库对隔离级别的支持和实现略有差异(比如 MySQL 的可重复读比标准更优)。下面从级别定义、解决的问题、数据库支持、性能特点等维度详细说明:
一、四大隔离级别
1. 读未提交(READ UNCOMMITTED)
- 定义:最低的隔离级别,允许一个事务读取另一个事务尚未提交的修改数据。
- 并发问题:会出现脏读、不可重复读、幻读(所有并发问题都存在)。
- 典型场景:几乎不使用,仅在对性能要求极致且能容忍脏数据的特殊场景下考虑。
- 性能:并发性能最高(因为几乎没有隔离限制)。
2. 读已提交(READ COMMITTED)
- 定义:一个事务只能读取另一个事务已经提交的修改数据,无法读取未提交的数据。
- 解决的问题:解决了脏读,但仍会出现不可重复读、幻读。
- 数据库支持:是 Oracle、SQL Server、PostgreSQL 等主流数据库的默认隔离级别。
- 性能:并发性能较高(仅次于读未提交)。
- 举例:事务 A 第一次读取账户余额为 1000 元,事务 B 修改余额为 800 元并提交,事务 A 再次读取时会得到 800 元(前后读取结果不一致,即不可重复读)。
3. 可重复读(REPEATABLE READ)
- 定义:保证同一事务内多次读取同一数据时,结果始终一致,不受其他事务提交的修改影响。
- 解决的问题:解决了脏读、不可重复读;MySQL 中额外解决了幻读(标准 SQL 的可重复读仍会出现幻读)。
- 数据库支持:是MySQL InnoDB 存储引擎的默认隔离级别。
- 实现原理(MySQL):通过MVCC(多版本并发控制) 为事务提供一致性快照,结合next-key lock(临键锁) 防止幻读(锁定数据范围,避免其他事务插入数据)。
- 性能:并发性能中等(平衡了隔离性和性能)。
- 举例:事务 A 全程读取账户余额都是 1000 元,即使事务 B 修改并提交了余额,事务 A 直到结束都只会看到 1000 元。
4. 串行化(SERIALIZABLE)
- 定义:最高的隔离级别,强制事务串行执行(相当于单线程处理事务),完全禁止并发操作。
- 解决的问题:解决了所有并发问题(脏读、不可重复读、幻读全部消失)。
- 实现方式:通过对整个数据范围加锁,事务执行时会阻塞其他事务的读写操作。
- 性能:并发性能最低(因为串行执行,相当于放弃了并发)。
- 典型场景:仅用于数据一致性要求极高的核心场景(如金融行业的资金清算、核心交易系统)。
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 并发性能 |
|---|---|---|---|---|
| 读未提交(READ UNCOMMITTED) | ✅ | ✅ | ✅ | 最高 |
| 读已提交(READ COMMITTED) | ❌ | ✅ | ✅ | 较高 |
| 可重复读(REPEATABLE READ) | ❌ | ❌ | ❌(MySQL) | 中等 |
| 串行化(SERIALIZABLE) | ❌ | ❌ | ❌ | 最低 |
四、主流数据库默认隔离级别
| 数据库产品 | 默认隔离级别 | 关键补充说明 |
|---|---|---|
| MySQL(InnoDB 引擎) | 可重复读(REPEATABLE READ) | 1. 并非标准的可重复读:通过MVCC+next-key lock解决了幻读(标准可重复读仍有幻读);2. MyISAM 引擎不支持事务,无隔离级别概念。 |
| Oracle | 读已提交(READ COMMITTED) | 1. 支持串行化(SERIALIZABLE)和只读隔离级别;2. 可通过ALTER SESSION SET ISOLATION_LEVEL修改级别。 |
| SQL Server | 读已提交(READ COMMITTED) | 1. 默认开启「读已提交快照隔离(RCSI)」,基于行版本控制减少锁竞争;2. 支持快照隔离(SNAPSHOT)、可序列化等级别。 |
| PostgreSQL | 读已提交(READ COMMITTED) | 1. 支持可重复读、序列化,且其可重复读实现接近 MySQL 的机制;2. 可通过SET TRANSACTION ISOLATION LEVEL临时修改。 |
| SQLite | 串行化(SERIALIZABLE) | 轻量级数据库,默认最高隔离级别,因并发场景少,性能影响可忽略。 |
| MongoDB(4.0 + 支持事务) | 读已提交(READ COMMITTED) | 分布式文档数据库,事务仅支持副本集,默认读已提交。 |

被折叠的 条评论
为什么被折叠?



