读写分离不是配完主从就能自动生效的,它必须由应用层或中间件显式路由——mysql自身不提供读写分离能力,只负责主从同步;主从复制必须先稳定运行,否则无法实现读写分离。

MySQL主从复制必须先跑稳
没同步就没分离,这是前提。别急着配应用,先盯住 SHOW SLAVE STATUS\G 里的三个关键项:
-
Slave_IO_Running: Yes和Slave_SQL_Running: Yes—— 任一为No,同步已断 -
Seconds_Behind_Master稳定在0或个位数(比如1)—— 超过 5 秒就要查延迟原因
常见卡点:Slave_SQL_Running: No 多因从库被手动改数据导致主键冲突,或主库执行了 DROP TABLE 这类 DDL;binlog_format 必须设为 ROW,MIXED 在某些场景会丢变更;从库建议加 read_only = 1,但 root 仍可写,得靠账号权限兜底。
MyBatis Plus 怎么让读走从库、写走主库
MyBatis Plus 自身不带路由逻辑,得靠 dynamic-datasource-spring-boot-starter 或 shardingsphere-jdbc。推荐前者,轻量、可控:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 主数据源 Bean 名必须叫
master,否则DynamicRoutingDataSource找不到默认源 - 用
@DS("slave")注解标在 service 方法上,比靠 SQL 关键字(如SELECT)自动识别更可靠——毕竟SELECT FOR UPDATE必须走主库 - 事务方法内嵌套的
@DS("slave")会被忽略,整个事务强制走主库,这是设计行为,不是 bug - 别把主库地址误填进从库列表,否则读请求会反打到主库,白配
ShardingSphere-JDBC 的 readwrite-splitting 配置要点
它比 dynamic-datasource 更成熟,但配置稍重,核心是明确声明主从关系:
-
write-data-source-name填主库逻辑名,read-data-source-names填从库逻辑名列表(逗号分隔),不能混入主库 - 默认负载均衡是
ROUND_ROBIN,但如果某个从库延迟高,请求分过去就拖慢整体——可换RANDOM,或用SQLHint强制指定从库 - 加
props.sql-show = true能看实际路由日志,确认SELECT是否真发到了从库 - 每个物理数据源(主/从)都要单独配 HikariCP 连接池,别共用一个配置块
ProxySQL 或 MyCAT 这类中间件怎么绕过应用改造
适合不想动代码的场景,但得额外运维一个服务:
- ProxySQL 用
mysql_query_rules匹配语句:^SELECT.*FOR UPDATE$→ 主库,^SELECT→ 从库组,其余全走主库;它还能监控Seconds_Behind_Master,超阈值自动切流量 - MyCAT 需先注册
write和read两个数据源,再通过schema.xml绑定逻辑库与物理库,注意账号权限要分开配(主库给INSERT/UPDATE/DELETE,从库只给SELECT) - 所有中间件都要求主从网络互通、3306 端口放行,且从库不能设
skip-networking
真正容易被忽略的是“强一致性边界”:事务内、SELECT FOR UPDATE、刚写完立刻查的场景,必须走主库——任何方案都不可能绕开这点,硬配从库只会查到脏数据或空结果。










