Java项目实现读写分离的核心是通过AbstractRoutingDataSource动态路由,主库处理写和强一致性读,从库承担普通读请求,结合ThreadLocal上下文、自定义注解与AOP控制切换,并配置连接池健康检查与故障降级策略。

Java 项目中配置多数据源实现读写分离,核心是让写操作走主库(Master),读操作自动路由到从库(Slave),同时保证事务一致性与切换透明性。关键不在堆配置,而在路由逻辑、数据源隔离和同步感知的协同设计。
主从数据源基础配置
先定义两个独立的数据源 Bean,分别对应主库和从库,使用 HikariCP 或 Druid 连接池,并通过 @ConfigurationProperties 绑定 yml 中的配置项:
- 主数据源加 @Primary 注解,确保 Spring 默认注入的是它
- 从数据源需显式设置 readOnly = true,避免意外写入
- 主库连接池可适当调高最大连接数(如 20),从库按读并发预估(如 30+)
- yml 示例中建议用不同前缀区分:
spring.datasource.master.*和spring.datasource.slave.*
动态路由数据源(AbstractRoutingDataSource)
这是实现运行时切换的核心组件。继承 AbstractRoutingDataSource,重写 determineCurrentLookupKey() 方法,根据上下文返回数据源标识(如 "master" 或 "slave"):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 路由依据通常来自 ThreadLocal 存储的标记,比如在 Service 层方法入口通过注解或手动设置
- 写操作(@Transactional、INSERT/UPDATE/DELETE)默认走 master;SELECT 查询默认走 slave
- 强一致性读(如刚写完立刻查)需主动切回 master,可通过自定义注解(如 @Master)触发切换
- 务必在每次请求结束时清理 ThreadLocal,防止线程复用导致路由错乱
读写识别与上下文控制
不能仅靠 SQL 关键字判断读写——MyBatis 的 XML 或注解方式可能绕过解析。更可靠的方式是结合业务语义控制:
立即学习“Java免费学习笔记(深入)”;
- 在 Service 方法上添加 @ReadOnly 或 @WriteOnly 自定义注解,配合 AOP 拦截设置数据源类型
- 事务方法(@Transactional)自动绑定 master,无需额外干预
- 对需要“读己之写”的场景(如下单后查订单),用 @Master 显式标注查询方法
- 避免在同一个事务内混用读写数据源,否则会抛出异常或引发连接泄漏
连接池与故障兜底策略
生产环境必须考虑从库不可用或延迟过大时的降级行为:
- 为从库配置 connection-test-query 和 validation-timeout,快速剔除失效节点
- 引入健康检查机制(如定时 ping 从库),发现异常时临时将读请求 fallback 到 master
- 从库列表支持多个(slave1, slave2…),路由层可做简单轮询或权重负载均衡
- 主库不可用时系统应整体熔断,而非尝试把读也切过去——那会压垮主库

















