Java中JDBC本身不支持读写分离与负载均衡,需借助ShardingSphere-JDBC、MyCat等中间件或Spring的AbstractRoutingDataSource自定义路由实现;核心是写操作走主库,读操作按策略(如轮询)分发至从库,并处理主从延迟、事务一致性及故障转移。

Java 中 JDBC 本身不直接支持读写分离和负载均衡,需要借助外部机制或中间件来实现。核心思路是:将写操作(INSERT/UPDATE/DELETE)路由到主库,读操作(SELECT)按策略分发到一个或多个从库,并在多个从库间做负载均衡。
1. 使用支持读写分离的数据库连接池或代理
最常用、最稳妥的方式是引入具备路由能力的中间层:
- ShardingSphere-JDBC:轻量级 Java 库,以 JDBC 驱动形式嵌入应用。通过配置主从数据源、读写分离规则和负载均衡策略(如轮询、随机、权重),自动拦截 SQL 并路由。无需改 SQL,只需调整数据源配置和少量 Java 初始化代码。
- MyCat / ShardingSphere-Proxy:独立代理服务,应用仍用标准 JDBC 连接 MyCat(伪装成 MySQL),由它完成解析、路由与结果合并。适合多语言环境,但增加部署运维复杂度。
-
Druid + 自定义路由 DataSource:Druid 本身不支持读写分离,但可封装一个
AbstractRoutingDataSource(Spring 提供),结合 ThreadLocal 标记当前是否强制走主库(如刚写完需立即读),再根据策略选择从库实例。
2. 基于 Spring 的动态数据源路由(轻量自研方案)
适用于中小项目,不依赖第三方分库分表框架:
- 定义多个
DataSourceBean:一个主库(masterDataSource),多个从库(slaveDataSource1,slaveDataSource2)。 - 继承
AbstractRoutingDataSource,重写determineCurrentLookupKey()方法,根据方法名(如是否含 “select”)、注解(如@ReadOnly)、或 ThreadLocal 中的标记,返回对应数据源 key。 - 用
LoadBalanceStrategy接口实现轮询/随机/权重等策略,每次获取从库时调用该策略选一个真实数据源。 - 注意事务边界:一旦开启事务,默认所有操作(包括 SELECT)都走主库,避免从库读到未提交或过期数据。
3. 注意事项与关键细节
读写分离不是“配好就能用”,容易踩坑:
立即学习“Java免费学习笔记(深入)”;
-
主从延迟问题:写入主库后立刻查从库,可能读不到最新数据。业务上要接受最终一致性,或对强一致性场景显式使用
@Transactional(readOnly = false)或自定义注解强制走主库。 - 连接泄漏风险:若用 ThreadLocal 传递路由上下文,务必在 Filter 或 AOP 的 finally 块中清理,否则线程复用会导致后续请求路由错误。
- 健康检查与故障转移:从库宕机时,负载均衡器应自动剔除异常节点。ShardingSphere 和 Druid 都支持心跳检测;自研方案需集成类似 HikariCP 的 health check 或自己实现。
-
不建议在 SQL 层硬编码库名:避免用
/*+ db:slave1 */ SELECT ...这类注释方式——耦合高、难维护、无法统一治理。
4. 简单示例:ShardingSphere-JDBC 配置片段(YAML)
以下为 Spring Boot + ShardingSphere-JDBC 的典型配置:
spring:
shardingsphere:
props:
sql-show: true
datasource:
names: master,slave1,slave2
master:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://master:3306/mydb
username: root
password: pwd
slave1:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://slave1:3306/mydb
username: root
password: pwd
slave2:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://slave2:3306/mydb
username: root
password: pwd
rules:
- !READWRITE_SPLITTING
dataSources:
pr_ds:
writeDataSourceName: master
readDataSourceNames: [slave1, slave2]
loadBalancerName: round_robin # 轮询策略
loadBalancers:
round_robin:
type: ROUND_ROBIN配置完成后,应用中所有 JdbcTemplate 或 MyBatis 的查询自动走从库,更新操作走主库,完全透明。


















