如果 Spring 的 @Transactional
隔离级别 和 数据库的隔离级别 不一致,最终生效的隔离级别取决于以下两种情况:
1. Spring 隔离级别优先级更高
-
Spring 的行为:
-
生效的隔离级别:
-
以 Spring 配置的隔离级别为准。
-
例如,
@Transactional(isolation = Isolation.READ_COMMITTED)
会强制将事务的隔离级别设置为READ COMMITTED
,即使数据库的默认隔离级别是REPEATABLE READ
。
-
2. 数据库隔离级别优先级更高
-
数据库的限制:
-
生效的隔离级别:
3. 你的问题:Spring 配置为 RC,MySQL 默认是 RR
-
情况分析:
-
Spring 配置了
@Transactional(isolation = Isolation.READ_COMMITTED)
,即RC
。 -
MySQL 的默认隔离级别是
REPEATABLE READ
,即RR
。
-
-
最终生效的隔离级别:
-
以 Spring 配置的隔离级别为准,即
READ COMMITTED
。 -
因为 MySQL 支持
READ COMMITTED
,Spring 会在开启事务时发送SET TRANSACTION ISOLATION LEVEL READ COMMITTED
的指令,覆盖 MySQL 的默认隔离级别。
-
4. 验证方法
你可以通过以下方式验证事务的隔离级别是否生效:
(1) 查看当前事务的隔离级别
在 MySQL 中,可以通过以下 SQL 查询当前会话的隔离级别:
sql
复制
SELECT @@tx_isolation; -- MySQL 5.x SELECT @@transaction_isolation; -- MySQL 8.x
(2) 测试隔离级别的行为
-
开启两个事务:
-
事务 A:更新数据但不提交。
-
事务 B:查询数据。
-
-
根据隔离级别的不同,事务 B 的查询结果会有所不同:
-
如果隔离级别是
READ COMMITTED
,事务 B 看不到事务 A 未提交的数据。 -
如果隔离级别是
READ UNCOMMITTED
,事务 B 可以看到事务 A 未提交的数据。
-
5. 代码示例
以下是一个 Spring 配置 READ COMMITTED
隔离级别的示例:
java
复制
@Service public class OrderService { @Autowired private OrderRepository orderRepository; // 使用 READ COMMITTED 隔离级别 @Transactional(isolation = Isolation.READ_COMMITTED) public void updateOrder(Order order) { orderRepository.save(order); } // 查询方法 @Transactional(isolation = Isolation.READ_COMMITTED) public Order getOrder(Long orderId) { return orderRepository.findById(orderId).orElse(null); } }
6. 总结
-
Spring 配置的隔离级别优先级更高:
-
如果 Spring 显式配置了隔离级别,且数据库支持该级别,则以 Spring 配置为准。
-
例如,Spring 配置
READ COMMITTED
,MySQL 默认是REPEATABLE READ
,最终生效的是READ COMMITTED
。
-
-
数据库的限制:
-
验证方法:
-
可以通过 SQL 查询或测试事务行为来验证隔离级别是否生效。
-
如果你有更多问题,欢迎继续讨论!
@Transactional(readOnly = true)什么含义