跳至正文
来两杯美式
返回

MySQL 知识系列(五):隔离级别、Spring 事务与查询流程

By 来两杯美式
发布于

事务隔离级别

查询与设置

-- 查询(MySQL 8.0 用 transaction_isolation 代替 tx_isolation)
SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;

-- 设置会话级
SET SESSION transaction ISOLATION LEVEL READ UNCOMMITTED;

四种隔离级别对比

隔离级别脏读不可重复读幻读加锁情况适用
READ UNCOMMITTED(读未提交)几乎不加锁几乎不用
READ COMMITTED(读已提交)写加 X 锁;读用 MVCC 快照读Oracle 默认
REPEATABLE READ(可重复读)RR 下用 Next-Key Lock 解决幻读MySQL 默认
SERIALIZABLE(串行化)读加 S 锁,写加 X 锁强一致性场景

💡 关键点

  • MySQL 的 RR 比 SQL 标准的 RR 更强——标准 RR 只解决”不可重复读”,幻读未解决;MySQL InnoDB 的 RR 用 Next-Key Lock 解决了幻读
  • Oracle、PostgreSQL 默认 RC,不解决幻读
  • 不可重复读”侧重单条记录值被修改;“幻读”侧重记录数量变化(被 INSERT/DELETE)

Spring 事务传播机制

Spring 的 Propagation 枚举定义了 7 种事务传播行为,核心关注”内外方法都有事务时怎么处理”

传播行为含义
REQUIRED(默认)外层有事务 → 加入外层;外层没事务 → 开启新事务。一起提交一起回滚
REQUIRES_NEW总是开启新事务,挂起外层事务;新事务执行完恢复外层
SUPPORTS外层有事务 → 加入;外层没事务 → 非事务方式执行
NOT_SUPPORTED不支持事务;外层有事务则挂起,内层执行完恢复
NESTED外层有事务 → 嵌套子事务(Savepoint);外层没事务 → 同 REQUIRED
MANDATORY必须在已有事务中执行,否则抛异常
NEVER必须在无事务中执行,否则抛异常

实战选型

多数据源事务管理

痛点

Spring 多数据源事务问题示意

默认 @Transactional 只能管单数据源事务。多个数据源时:

解决方案:ChainedTransactionManager

Spring 提供的链式事务管理器

@Bean
public PlatformTransactionManager transactionManager() {
    return new ChainedTransactionManager(
        txManagerDataSource1,    // 按顺序开启
        txManagerDataSource2
    );
}

原理:按设置顺序依次开启事务倒序提交。任何一步失败则整体回滚。

A 开启 → B 开启 → A 执行 → B 执行 → B 提交 → A 提交

⚠️ ChainedTransactionManager 已废弃(Spring 5.x),原因:它本质是两阶段提交(2PC)的非标准实现,无法保证严格一致性。生产推荐:使用 Seata / Atomikos 等真正支持 XA 事务的分布式事务方案。

查询请求处理流程

完整流程

1. 客户端发 SQL 到服务器
2. 服务器检查查询缓存是否命中(MySQL 8.0 已移除此步)
3. 分析器解析 SQL → 优化器生成执行计划
4. 根据执行计划,调用存储引擎 API 查数据
5. 将结果返回客户端

查询缓存细节(仅 MySQL 5.7 及之前)

SHOW VARIABLES LIKE 'query_cache_type';     -- ON / OFF / DEMAND
SHOW VARIABLES LIKE 'query_cache_size';     -- 缓存内存大小
SHOW VARIABLES LIKE 'query_cache_limit';    -- 单条结果最大缓存值

特性:

DEMAND 模式下手动控制:

SELECT SQL_CACHE * FROM user WHERE id = 1;       -- 走缓存
SELECT SQL_NO_CACHE * FROM user WHERE id = 1;    -- 不走缓存

实战建议

  1. 优先用默认 RR:MySQL 的 RR 解决了幻读,比标准 RR 更强
  2. 慎用 SERIALIZABLE:并发性能差,除非对一致性要求极强
  3. @Transactional 加在哪个方法上:默认只对 public 方法 + 外部调用生效,自调用(this.xxx)不触发代理
  4. 多数据源优先选 Seata 分布式事务,不要用 ChainedTransactionManager
  5. 慢查询日志一定要开long_query_time=0.1(100ms)

下一篇会讲”实战调优”:SQL 注入防护(PreparedStatement)、MySQL 8.0 新特性、版本选择与升级方法论。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
所属专题
MySQL
第 5 / 9 篇
查看系列全部文章
  1. 01.MySQL 知识系列(一):整体架构与存储引擎
  2. 02.MySQL 知识系列(二):索引结构与查询原理
  3. 03.MySQL 知识系列(三):锁机制与并发控制
  4. 04.MySQL 知识系列(四):日志系统:redo log、undo log、binlog
  5. 05.MySQL 知识系列(五):隔离级别、Spring 事务与查询流程
  6. 06.MySQL 知识系列(六):SQL 注入、版本特性与容量评估
  7. 07.MySQL 知识系列(七):SQL 调优(一)—— EXPLAIN 执行计划
  8. 08.MySQL 知识系列(八):SQL 调优(二)—— 索引设计与调优工具
  9. 09.MySQL 知识系列(九):CASE 语句、乐观锁与悲观锁实战

上一篇
Redis 知识系列(三):持久化与高可用
下一篇
Redis 知识系列(二):高效使用