事务的隔离级别是数据库管理系统(DBMS)为了保证事务操作的一致性和并发性而提供的一种机制,用于定义多个事务并发执行时,数据访问的可见性程度。
在 SQL 标准中,事务隔离级别分为 4 种,由低到高分别为:
1. 读未提交(Read Uncommitted)
- 特点:一个事务可以读取另一个事务未提交的数据。
- 可能出现的问题:
- 脏读(Dirty Read):读取到另一个事务尚未提交的修改数据,如果该事务回滚,读到的数据就会变成无效数据。
- 性能:并发性能高,但数据安全性低。
- 应用场景:几乎不用,数据一致性要求低的场景。
示例:
事务 A 修改数据未提交,事务 B 可以读取到 A 修改后的数据。
2. 读已提交(Read Committed)
- 特点:一个事务只能读取另一个事务已提交的数据。
- 解决的问题:
- 避免脏读。
- 可能出现的问题:
- 不可重复读(Non-repeatable Read):在同一事务内,读取同一数据两次,第二次读取时,数据被另一个事务修改,导致结果不一致。
- 性能:是大多数数据库的默认隔离级别(如 Oracle)。
- 应用场景:数据一致性要求一般的场景。
示例:
- 事务 A 修改数据并提交,事务 B 读取时能看到事务 A 提交后的数据。
3. 可重复读(Repeatable Read)
- 特点:同一事务内多次读取数据的结果是一样的,保证了数据的一致性。
- 解决的问题:
- 避免脏读。
- 避免不可重复读。
- 可能出现的问题:
- 幻读(Phantom Read):在同一事务中,读取数据时,另一事务插入了新数据,导致结果集不一致。
- 性能:大部分数据库支持(如 MySQL 的默认隔离级别)。
- 应用场景:数据一致性要求高的场景。
示例:
- 事务 A 读取数据,事务 B 修改数据并提交,事务 A 再次读取时,数据与第一次一致,但事务 B 插入新行会导致幻读。
4. 串行化(Serializable)
- 特点:最高的隔离级别,事务顺序执行,避免所有并发问题。
- 解决的问题:
- 避免 脏读、不可重复读 和 幻读。
- 性能:并发性能最低,事务必须一个接一个地执行,通常通过锁表实现。
- 应用场景:对数据一致性要求极高的场景,如银行账户、金融交易等。
示例:
- 所有事务按顺序执行,完全避免并发问题。
4 种隔离级别总结对比
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
|---|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 | 最高 |
| 读已提交 | 避免 | 可能 | 可能 | 高 |
| 可重复读 | 避免 | 避免 | 可能 | 中 |
| 串行化 | 避免 | 避免 | 避免 | 最低 |
事务隔离级别的选择
- 读未提交:适用于对性能要求极高且数据一致性要求极低的场景(几乎不用)。
- 读已提交:大部分应用的默认选择(Oracle 默认)。
- 可重复读:MySQL 的默认级别,适用于大多数业务场景。
- 串行化:适用于数据一致性要求极高的场景,但性能损耗大。
数据库的默认隔离级别
- MySQL:默认隔离级别为 可重复读(Repeatable Read)。
- Oracle:默认隔离级别为 读已提交(Read Committed)。
- SQL Server:默认隔离级别为 读已提交(Read Committed)。
总结
事务的隔离级别通过控制数据访问的并发性和一致性,解决了 脏读、不可重复读 和 幻读 等问题。在实际应用中,需要根据系统的性能和数据一致性要求选择合适的隔离级别。
以下是结合实际业务场景的事务隔离级别示例,帮助理解事务隔离级别及其在不同业务中的应用。
业务场景示例
假设有一个电商系统,包含订单管理和库存管理两个模块,涉及用户下单、支付和库存扣减操作。将探讨不同事务隔离级别下可能出现的问题及其解决方案。
1. 读未提交(Read Uncommitted)
场景:用户下单时读取了未提交的库存数据,导致显示错误的库存。
- 业务过程:
- 用户A下单,开始一个事务,扣减商品库存(但未提交)。
- 用户B在此时查询库存,读取到未提交的数据,发现库存已经减少。
- 如果用户A的事务回滚,用户B看到的库存数据是错误的。
示例代码:
用户A操作(扣减库存但未提交):
BEGIN;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1001;
-- 模拟未提交事务
用户B操作(查询库存):
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
SELECT stock FROM inventory WHERE product_id = 1001;
COMMIT;
风险:
用户B查询到了用户A未提交的库存更新数据,导致脏读。这种情况下用户看到的库存数据并不准确。
2. 读已提交(Read Committed)
场景:用户支付时多次查询订单状态,导致不可重复读问题。
- 业务过程:
- 用户A查询订单状态为“待支付”。
- 另一个事务(如用户B或后台操作)修改订单状态为“已支付”并提交。
- 用户A再次查询订单状态,发现状态变为“已支付”。
示例代码:
用户B操作(提交订单支付):
BEGIN;
UPDATE orders SET status = '已支付' WHERE order_id = 123;
COMMIT;
用户A操作(查询订单状态):
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT status FROM orders WHERE order_id = 123; -- 第一次读取,状态是“待支付”
-- 等待用户B更新状态
SELECT status FROM orders WHERE order_id = 123; -- 第二次读取,状态变为“已支付”
COMMIT;
风险:
用户A同一事务中两次查询订单状态,结果不一致,出现了不可重复读问题。
3. 可重复读(Repeatable Read)
场景:用户在购物车中多次读取商品价格,价格保持一致。
- 业务过程:
- 用户A将商品添加到购物车,读取商品价格为
100 元。 - 另一个事务(如商家修改价格)将商品价格更新为
120 元。 - 用户A再次读取商品价格,仍然显示
100 元,保证了一致性。
- 用户A将商品添加到购物车,读取商品价格为
示例代码:
商家操作(修改商品价格):
BEGIN;
UPDATE products SET price = 120 WHERE product_id = 1001;
COMMIT;
用户A操作(读取商品价格):
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT price FROM products WHERE product_id = 1001; -- 第一次读取价格 100 元
-- 等待商家修改价格
SELECT price FROM products WHERE product_id = 1001; -- 第二次读取价格依然是 100 元
COMMIT;
结果:
在 可重复读 隔离级别下,用户A两次读取商品价格一致,避免了不可重复读问题。
4. 串行化(Serializable)
场景:防止多个用户同时下单导致超卖问题。
- 业务过程:
- 用户A查询库存,显示有
1 件。 - 用户B也查询库存,显示有
1 件。 - 两个用户同时下单,导致库存扣减为
-1,发生超卖。
- 用户A查询库存,显示有
串行化 隔离级别可以避免这种并发问题,因为事务按顺序执行。
示例代码:
用户A操作(下单):
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT stock FROM inventory WHERE product_id = 1001; -- 查询库存 1 件
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1001;
COMMIT;
用户B操作(下单):
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT stock FROM inventory WHERE product_id = 1001; -- 等待用户A事务完成
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1001;
COMMIT;
结果:
在 串行化 隔离级别下,用户B的事务必须等待用户A的事务完成后才能执行,避免了库存超卖问题。
总结:业务示例与风险对比
| 隔离级别 | 业务场景示例 | 问题 |
|---|---|---|
| 读未提交 | 查询未提交库存 | 脏读(读取未提交数据) |
| 读已提交 | 查询订单状态 | 不可重复读(结果不一致) |
| 可重复读 | 查询商品价格 | 幻读(新增数据影响结果集) |
| 串行化 | 防止库存超卖 | 无并发问题,性能最低 |
实际业务选择
- 读已提交(Read Committed):
- 大多数业务场景,如订单状态查询。
- 可重复读(Repeatable Read):
- 解决不可重复读问题,如商品价格读取、银行账户查询。
- 串行化(Serializable):
- 对数据一致性要求极高的业务场景,如库存扣减防止超卖。
970

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



