只读事务@Transactional(readOnly = true)是数据库连接层的重要优化信号,可降低锁开销、减少日志写入、提升连接复用率;需方法级精准配置,依赖支持只读语义的数据源和连接池,并配合读写分离实现性能提升。

在 Java 应用中,只读事务(readOnly = true)不是“摆设”,而是数据库连接层的重要优化信号。它不改变业务逻辑,但能显著降低锁开销、减少日志写入、提升连接复用率,尤其在高并发查询场景下效果明显。
核心配置方式:@Transactional(readOnly = true)
只需在查询方法上添加该属性即可,Spring 会将其透传给底层 JDBC 连接:
- 方法级最常用:精准控制,不影响其他操作
- 类级慎用:若 Service 中混有写操作,会导致运行时报错(如
Connection is read-only) - 必须搭配支持只读语义的数据源(如 MySQL 的
setReadOnly(true)),主流连接池(HikariCP、Druid)均默认支持
配合 dynamic-datasource 实现读写分离
只读事务 + 主从路由是性能倍增组合。dynamic-datasource 会自动将 @Transactional(readOnly = true) 的方法路由到从库(前提是已配置 @DS("slave") 或启用自动识别):
- 无需手动加
@DS注解,框架可基于 readOnly 属性智能选源 - 若显式指定
@DS("slave"),建议同时加readOnly = true,双重保障 - 注意:跨库事务(如主库写 + 从库查)不能放在同一事务内,否则从库查询可能读不到刚写入的数据(主从延迟)
关键细节与避坑点
只读事务生效依赖多个环节协同,缺一不可:
立即学习“Java免费学习笔记(深入)”;
- 事务必须真正开启:方法需被 Spring 代理调用(public 方法 + 外部调用),私有或 self-invocation 会失效
- 数据库引擎要支持事务:MySQL 使用 InnoDB;MyISAM 不支持事务,
readOnly无意义 - 避免在只读事务里执行更新语句:一旦触发 INSERT/UPDATE/DELETE,JDBC 驱动会抛出
SQLException: Connection is read-only - 连接池需启用 readOnly 传递:HikariCP 默认开启,Druid 需确认
defaultReadOnly=true配置项
实际效果参考
在典型电商列表页查询中,启用 readOnly = true 后:
- 平均响应时间下降约 20%~35%(源于更轻量的连接初始化和更少的 undo log)
- 主库 CPU 使用率降低 15%~25%,因大量读请求被分流至从库
- 数据库连接池活跃连接数更稳定,避免因长事务占用连接



















