Java中事务隔离级别是数据库机制,Java通过JDBC或Spring等框架将隔离指令传递给数据库;SQL标准定义四种级别:READ UNCOMMITTED(允许脏读、不可重复读、幻读)、READ COMMITTED(禁止脏读,允许后两者)、REPEATABLE READ(禁止脏读和不可重复读,MySQL通过MVCC+Next-Key Lock也防幻读)、SERIALIZABLE(完全禁止三类问题,但性能最差)。

Java 中事务隔离级别的设置和理解,核心在于两点:数据库层面的隔离机制和Java 应用层的控制方式。它不是 Java 自己定义的规则,而是通过 JDBC 或 ORM 框架(如 Spring、Hibernate)把 Java 的事务声明“翻译”成数据库能识别的隔离指令。
什么是事务隔离级别
事务隔离级别决定一个事务能看到其他并发事务做到哪一步的数据。它解决的是多事务同时操作时的三类典型问题:
- 脏读:读到别人还没提交的数据
- 不可重复读:同一事务内两次查同一行,结果变了(因别人改完并提交)
- 幻读:同一事务内两次查同一范围,行数变了(因别人插入/删除了符合查询条件的新记录)
SQL 标准定义了四种级别,从低到高依次是:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 实际常用度 |
|---|---|---|---|---|
READ UNCOMMITTED |
✅ 允许 | ✅ 允许 | ✅ 允许 | 极少用 |
READ COMMITTED |
❌ 禁止 | ✅ 允许 | ✅ 允许 | Oracle 默认,广泛适用 |
REPEATABLE READ |
❌ 禁止 | ❌ 禁止 | ⚠️ MySQL 默认解决,标准中仍允许 | MySQL InnoDB 默认 |
SERIALIZABLE |
❌ 禁止 | ❌ 禁止 | ❌ 禁止 | 安全但性能差,慎用 |
注意:MySQL 的
REPEATABLE READ通过 MVCC + Next-Key Lock(间隙锁+行锁) 实际上也防止了幻读;而 SQL 标准定义中它并不保证防幻读,这点容易混淆。立即学习“Java免费学习笔记(深入)”;
Java 中怎么设置隔离级别
✅ 方式一:JDBC 原生设置(Connection 层)
Connection conn = dataSource.getConnection(); conn.setTransactionIsolation(Connection.TRANSACTION_ISOLATION_REPEATABLE_READ); conn.setAutoCommit(false); // 执行 SQL... conn.commit();
可用常量:
TRANSACTION_ISOLATION_READ_UNCOMMITTEDTRANSACTION_ISOLATION_READ_COMMITTEDTRANSACTION_ISOLATION_REPEATABLE_READTRANSACTION_ISOLATION_SERIALIZABLE
⚠️ 注意:必须在开启事务前设置(即 setAutoCommit(false) 之后、执行 SQL 之前),否则可能无效。
✅ 方式二:Spring 声明式事务(推荐)
在方法或类上加 @Transactional 注解:
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
// 扣款、入账等操作
}Spring Isolation 枚举对应关系:
-
Isolation.DEFAULT→ 使用数据库默认级别(如 MySQL 是REPEATABLE READ,Oracle 是READ COMMITTED) Isolation.READ_UNCOMMITTEDIsolation.READ_COMMITTEDIsolation.REPEATABLE_READIsolation.SERIALIZABLE
✅ 小技巧:若只希望某次查询使用更高隔离,也可用
@Transactional(readOnly = true, isolation = Isolation.SERIALIZABLE)临时提升,但不建议滥用。
✅ 方式三:Hibernate / JPA(通过属性或注解)
- 在
application.properties中全局配置:spring.jpa.properties.hibernate.connection.isolation=4 # 对应 REPEATABLE_READ
- 或在
@Transactional中直接指定,同 Spring 方式。
怎么选合适的隔离级别
读已提交(READ COMMITTED)
大多数业务场景首选。避免脏读,性能好,兼容性强。适合订单查询、用户资料查看等对“实时一致性”要求不高、但不能容忍脏数据的场景。可重复读(REPEATABLE READ)
适合需要多次读取同一数据且要求结果稳定的情况,比如银行余额查询、库存预占。MySQL 默认,开箱即用,但要注意它在某些复杂 JOIN 或子查询下仍可能有边界问题。串行化(SERIALIZABLE)
只在极少数强一致性场景下使用,例如金融核心账务冲正、跨库双写校验。它会让数据库加范围锁甚至表锁,容易引发阻塞和死锁,务必配合短事务 + 重试机制。读未提交(READ UNCOMMITTED)
基本不用。除非做日志分析、监控统计等完全不关心准确性的只读场景。
关键提醒
- 隔离级别是数据库能力,Java 只是传递指令。不同数据库实现差异大(如 PostgreSQL 的
REPEATABLE READ不防幻读,而 MySQL 防)。 - Spring 的
@Transactional隔离设置只对受管事务生效(即由 Spring 代理的方法),私有方法、this.调用、非 Spring Bean 中的事务不受影响。 -
SERIALIZABLE在 MySQL 中会退化为SELECT ... LOCK IN SHARE MODE或FOR UPDATE行为,实际效果取决于 SQL 写法。 - 单纯提高隔离级别 ≠ 解决所有并发问题。超卖、写偏斜(Write Skew)等还需靠应用层校验、乐观锁、分布式锁或业务补偿来兜底。
不复杂但容易忽略。


















