Spring Boot集成Aurora PostgreSQL读写分离时@Transactional(readOnly=true)引发延迟升高的最优配置问询
我之前在维护Spring Boot + Aurora PostgreSQL主从架构的服务时,遇到过和你完全一样的问题——用@Transactional(readOnly=true)路由到只读副本后,因为额外的SET SESSION CHARACTERISTICS语句导致延迟飙升。下面是我摸索出来的最优配置方案,核心思路是只做数据源路由,完全跳过连接的只读状态设置:
1. 调整自定义RoutingDataSource逻辑,去掉连接只读属性设置
你的自定义路由数据源可能在切换到只读节点后,会自动调用connection.setReadOnly(true),这正是触发JDBC驱动执行SET SESSION CHARACTERISTICS READ ONLY的根源。因为你只需要路由,不需要实际标记会话只读,所以要把这部分逻辑删掉:
public class CustomRoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { // 只负责判断路由键,不修改任何连接属性 return TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? "reader" : "writer"; } // 确保父类不会自动设置连接只读(如果你的实现里有相关逻辑的话) @Override protected Connection doGetConnection(Object lookupKey) throws SQLException { Connection conn = super.doGetConnection(lookupKey); // 不要调用 conn.setReadOnly(...)! return conn; } }
2. 配置Hikari连接池,彻底禁用只读会话设置
针对主、从数据源分别配置Hikari,重点给只读副本数据源加上两个关键配置,完全阻止JDBC驱动执行额外的SET语句:
主数据源(Writer)配置
spring.datasource.writer.url=jdbc:postgresql://your-aurora-writer-endpoint:5432/your-db spring.datasource.writer.username=xxx spring.datasource.writer.password=xxx spring.datasource.writer.hikari.read-only=false # 主数据源保持默认即可,不需要额外的readOnlyMode配置
只读数据源(Reader)配置
spring.datasource.reader.url=jdbc:postgresql://your-aurora-reader-endpoint:5432/your-db spring.datasource.reader.username=xxx spring.datasource.reader.password=xxx # 核心1:告诉Hikari不要把连接标记为只读 spring.datasource.reader.hikari.read-only=false # 核心2:告诉PG-JDBC驱动完全忽略只读属性的设置,不执行任何SET语句 spring.datasource.reader.hikari.data-source-properties.readOnlyMode=ignore
3. 禁用JOOQ的自动只读会话设置
JOOQ默认会根据@Transactional(readOnly=true)注解自动设置会话只读,这也会触发额外的数据库操作。你需要在JOOQ的配置里明确禁用这个行为:
@Bean public DefaultConfiguration jooqConfiguration(DataSource dataSource, TransactionManager transactionManager) { DefaultConfiguration config = new DefaultConfiguration(); config.set(dataSource); config.set(new SpringTransactionProvider(transactionManager)); // 关键:禁用JOOQ自动设置只读会话 config.set(new Settings().setExecuteReadOnly(false)); return config; }
4. 验证效果
配置完成后,你可以开启PG的日志或者用JDBC驱动的日志,确认不会再出现SET SESSION CHARACTERISTICS READ ONLY和SET SESSION CHARACTERISTICS READ WRITE语句。此时只读副本的查询延迟应该会和主节点基本一致——毕竟你只是把请求路由过去,没有额外的数据库往返开销了。
另外,你提到只读副本仅处理1%的流量,完全不用担心负载问题,这个配置方案不会带来任何额外的性能损耗。
内容的提问来源于stack exchange,提问作者frm

