Spring事务隔离级别与数据库隔离级别对应关系
一、Spring与数据库隔离级别对应表
| Spring事务隔离级别 | 对应数据库隔离级别 | 说明 |
|---|---|---|
| DEFAULT | 使用底层数据库的默认隔离级别 | Spring不干预,完全依赖数据库<br>(最常用,占95%) |
| READ_UNCOMMITTED | READ UNCOMMITTED | 读未提交 |
| READ_COMMITTED | READ COMMITTED | 读已提交 |
| REPEATABLE_READ | REPEATABLE READ | 可重复读 |
| SERIALIZABLE | SERIALIZABLE | 串行化 |
- Spring只是在应用层声明隔离级别
- 最终执行还是由数据库来保证
- Spring的5种 = 数据库标准的4种 + 1个DEFAULT
二、四种标准隔离级别详解
| 隔离级别 | 脏读<br>Dirty Read | 不可重复读<br>Non-Repeatable Read | 幻读<br>Phantom Read | 性能 | 并发度 |
|---|---|---|---|---|---|
| READ_UNCOMMITTED<br>读未提交 | ❌ 会发生 | ❌ 会发生 | ❌ 会发生 | 最高 | 最高 |
| READ_COMMITTED<br>读已提交 | ✅ 已解决 | ❌ 会发生 | ❌ 会发生 | 较高 | 较高 |
| REPEATABLE_READ<br>可重复读 | ✅ 已解决 | ✅ 已解决 | ❌ 会发生<br>⚠️ MySQL除外 | 较低 | 较低 |
| SERIALIZABLE<br>串行化 | ✅ 已解决 | ✅ 已解决 | ✅ 已解决 | 最低 | 最低 |
三、主流数据库的默认隔离级别
| 数据库 | 默认隔离级别 | 说明 |
|---|---|---|
| MySQL (InnoDB) | REPEATABLE_READ<br>可重复读 | MySQL的REPEATABLE_READ通过MVCC + Next-Key Lock<br>实际上也解决了幻读问题 |
| Oracle | READ_COMMITTED<br>读已提交 | Oracle更注重并发性能 |
| PostgreSQL | READ_COMMITTED<br>读已提交 | 同Oracle |
| SQL Server | READ_COMMITTED<br>读已提交 | 同Oracle |
| SQLite | SERIALIZABLE<br>串行化 | 因为SQLite主要用于单用户场景 |
四、不同隔离级别的实际表现
| 时间 | 事务A | 事务B | READ_UNCOMMITTED | READ_COMMITTED | REPEATABLE_READ | SERIALIZABLE |
|---|---|---|---|---|---|---|
| T1 | BEGIN | |||||
| T2 | 读余额 | 1000 | 1000 | 1000 | 1000 | |
| T3 | BEGIN | |||||
| T4 | 改为500 | |||||
| T5 | 读余额 | 500 (脏读) | 1000 | 1000 | 1000 | |
| T6 | COMMIT | |||||
| T7 | 读余额 | 500 | 500 (不可重复读) | 1000 | 1000 | |
| T8 | COMMIT |
- READ_UNCOMMITTED:T5读到了未提交的500(脏读)
- READ_COMMITTED:T5读到1000,T7读到500(不可重复读)
- REPEATABLE_READ:T5、T7都读到1000(可重复读)
- SERIALIZABLE:事务B要等事务A结束才能执行(串行)
五、Spring中如何指定隔离级别
六、实际项目中的使用建议
| 业务场景 | 推荐隔离级别 | 理由 |
|---|---|---|
| 普通业务操作 | DEFAULT<br>(不指定) | 用数据库默认即可<br>占95%的场景 |
| 报表查询、数据统计 | READ_UNCOMMITTED | 允许读脏数据,提高性能<br>对实时性要求不高 |
| 电商订单查询 | READ_COMMITTED | 避免脏读即可<br>Oracle/PostgreSQL默认 |
| 账户余额查询 | REPEATABLE_READ | 事务内多次查询要一致<br>MySQL默认 |
| 金融转账、库存扣减 | REPEATABLE_READ<br>或SERIALIZABLE | 强一致性要求 |
| 秒杀、抢购 | 乐观锁 + DEFAULT | 用版本号控制,不提高隔离级别<br>避免性能问题 |
| 分布式事务 | 通常用DEFAULT | 隔离级别由分布式事务框架管理 |
七、常见误区和坑
- 优先用乐观锁(版本号)
- 然后考虑悲观锁(SELECT FOR UPDATE)
- 最后才考虑提高隔离级别
八、性能对比和并发度
| 隔离级别 | 加锁情况 | 并发TPS | 适用场景 |
|---|---|---|---|
| READ_UNCOMMITTED | 几乎不加锁 | 最高(≈10000) | 日志、监控数据 |
| READ_COMMITTED | 读不加锁,写加锁 | 较高(≈8000) | 大部分OLTP业务 |
| REPEATABLE_READ | 读写都加锁(或MVCC) | 中等(≈5000) | 需要一致性读取 |
| SERIALIZABLE | 范围锁,串行执行 | 最低(≈1000) | 金融核心交易 |
九、加分项:MVCC机制
- InnoDB通过undo log保存数据的历史版本
- 每个事务读取的是数据的快照版本
- 读不加锁,写才加锁
- 实现了读写不阻塞
总结
- Spring的5种隔离级别 = DEFAULT + 数据库标准的4种
- MySQL默认REPEATABLE_READ,Oracle默认READ_COMMITTED
- 95%的场景用DEFAULT(数据库默认)就够了
- 隔离级别越高,性能越差,要权衡
- MySQL的REPEATABLE_READ通过MVCC解决了大部分幻读
- 不要随意修改隔离级别
- 优先用乐观锁解决并发问题
- 特殊场景(金融、库存)才考虑提高隔离级别
- 理解数据库的默认行为,不要过度设计

浙公网安备 33010602011771号