🧑💻 关于我
三年全栈实践 · Vue + Java 真实项目沉淀,可复用代码与踩坑解法
👋 关注我,收获实战经验,少走弯路
📬 绿泡泡:**
it全栈小屋**🔗 代码获取:https://gitee.com/xiaohelikesleep
🔗 CSDN:https://blog.csdn.net/interest_ing_
🚀 Spring Boot + MySQL 主从复制实战指南
从零搭建生产级读写分离架构 | ShardingSphere-JDBC + MyBatis-Plus + Docker
💭 写在前面
还记得第一次遇到数据库性能瓶颈时的窘境吗?
用户量暴涨,数据库连接数告警,CPU飙升到90%,页面加载越来越慢... 这时候,主从复制 + 读写分离就是你的救命稻草。
今天手把手带你从零搭建一套生产级的读写分离架构,5分钟上手,30分钟精通。
🤔 为什么需要主从复制?
❌ 单库的痛点
- 读写在同一个库,性能瓶颈明显
- 无法横向扩展,升级硬件成本高昂
- 单点故障风险,数据安全性差
✅ 主从复制的优势
- 读写分离 :写操作走主库,读操作走从库,性能提升 3-5 倍
- 负载均衡:多个从库分担读取压力
- 数据备份:从库实时同步,容灾能力强
- 高可用性:主库故障可快速切换到从库
📖 你能学到什么?
- 🔧 Docker Compose 部署 MySQL 主从集群(1主1从)
- ⚙️ ShardingSphere-JDBC 实现透明化读写分离
- 🎯 MyBatis-Plus 简化 CRUD 开发
- 🧪 集成测试 验证路由正确性
- 📊 日志监控 观察 SQL 实际执行路径
🏗️ 整体架构
┌─────────────────────────────────────────────┐
│ Spring Boot Application │
│ │
│ Controller → Service → Mapper │
│ ↓ │
│ ┌─────────────────────┐ │
│ │ShardingSphere-JDBC │ │
│ │ 智能SQL路由引擎 │ │
│ └──────────┬──────────┘ │
└─────────────────────────┼────────────────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Master DB │ 复制 │ Slave DB │
│ (主库:3307) │────────────▶│ (从库:3308) │
│ │ │ │
│ ✓ 写操作 │ │ ✓ 读操作 │
│ INSERT/UPDATE│ │ SELECT │
│ DELETE │ │ │
└──────────────┘ └──────────────┘
路由规则:
操作类型 SQL 示例 路由目标 说明 写入 INSERT / UPDATE / DELETE → Master (3307) 保证数据一致性 查询 SELECT * FROM user → Slave (3308) 减轻主库压力 事务 @Transactional → Master (3307) 事务内强制走主库
🛠️ 技术栈
组件 版本 作用 Spring Boot 3.5.14 应用框架 MyBatis-Plus 3.5.9 ORM框架 ShardingSphere-JDBC 5.8.1 读写分离中间件 MySQL 8.4 关系型数据库 Docker Compose - 容器编排
为什么选择 ShardingSphere?
- ✅ Jar包形式嵌入应用,无需额外部署代理服务
- ✅ 对业务代码零侵入,无需修改 DAO 层代码
- ✅ Apache 顶级项目,社区活跃,文档完善
🚀 快速上手(5分钟)
前置条件
- ☑️ JDK 17+
- ☑️ Maven 3.6+
- ☑️ Docker Desktop
- ☑️ Git
Step 1:克隆项目
git clone https://gitee.com/xiaohelikesleep/note-of-spring
cd note-of-spring/spring-mysql-slave
Step 2:启动 MySQL 主从集群 ⏱️ 30秒
docker-compose up -d
docker-compose ps
预期输出:
Name Command State Ports
----------------------------------------------------------------------
mysql-master docker-entrypoint.sh mysqld ... Up 0.0.0.0:3307->3306/tcp
mysql-slave docker-entrypoint.sh mysqld ... Up 0.0.0.0:3308->3306/tcp
Step 3:配置主从复制 🔗
在主库创建复制用户:
docker exec -it mysql-master mysql -uroot -p'root@123456' -e "
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
"
记录 File 和 Position 的值!
在从库配置复制源:
docker exec -it mysql-slave mysql -uroot -p'root@123456' -e "
CHANGE MASTER TO
MASTER_HOST='mysql-master',
MASTER_USER='repl',
MASTER_PASSWORD='repl@123456',
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=1234,
GET_MASTER_PUBLIC_KEY=1;
START SLAVE;
SHOW SLAVE STATUS\G
"
验证成功标志:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
🎉 看到两个 Yes,主从复制就配置好了!
Step 4:初始化数据库
docker exec -i mysql-master mysql -uroot -p'root@123456' master_slave_db < src/main/resources/db/schema.sql
Step 5:启动应用
mvn spring-boot:run
💡 实战验证
创建用户(写操作 → 主库)
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"username":"zhangsan","email":"zhangsan@example.com","phone":"13800138000"}'
控制台日志:
SQL Route: dataSourceName: master ← 走了主库!
查询用户(读操作 → 从库)
curl http://localhost:8080/api/users/1
控制台日志:
SQL Route: dataSourceName: slave ← 走了从库!
🔍 核心原理
ShardingSphere 路由流程
应用程序发送 SQL
↓
Step 1: SQL 解析 → 生成AST
↓
Step 2: SQL 路由 → 判断类型 + 事务上下文
↓
Step 3: SQL 执行 → 连接对应的数据源
↓
目标数据库(Master 或 Slave)
关键配置解读
spring:
shardingsphere:
datasource:
names: master,slave
master:
url: jdbc:mysql://localhost:3307/master_slave_db
slave:
url: jdbc:mysql://localhost:3308/master_slave_db
rules:
readwrite-splitting:
data-sources:
ds:
write-data-source-name: master
read-data-source-names:
- slave
load-balancer-name: round-robin
负载均衡策略
策略 说明 适用场景 ROUND_ROBIN 轮询分配 从库性能相近 RANDOM 随机分配 简单场景 WEIGHT 按权重分配 从库性能不均
📁 项目结构
spring-mysql-slave/
├── docker-compose.yml # MySQL主从集群
├── master.cnf / slave.cnf # MySQL配置
├── pom.xml # Maven依赖
│
└── src/main/
├── java/com/hfh/api/
│ ├── ApiApplication.java # 启动类
│ ├── entity/User.java # 实体类
│ ├── mapper/UserMapper.java # 数据访问层
│ ├── service/UserService.java # 业务层
│ └── controller/UserController.java # 控制器
│
└── resources/
├── application.yaml # 核心配置
└── db/schema.sql # 建表脚本
❓ 常见问题
Q1: 连接被拒绝?
docker-compose ps # 检查容器状态
docker-compose up -d # 重启容器
sleep 10 # 等待MySQL初始化
Q2: 复制报错 "Last_IO_Error"?
# 重新获取Master Status
docker exec -it mysql-master mysql -uroot -p'root@XH2001!' -e "SHOW MASTER STATUS;"
# 重新配置从库
CHANGE MASTER TO ... # 使用新的File和Position
Q3: 如何确认读写分离生效?
方法1:查看日志 (已配置 sql-show: true)
SQL Route: dataSourceName: slave ← 看这里!
方法2:分别查询主从库
docker exec -it mysql-master mysql -uroot -p'root@XH2001!' -e "SELECT * FROM master_slave_db.user;"
docker exec -it mysql-slave mysql -uroot -p'root@XH2001!' -e "SELECT * FROM master_slave_db.user;"
Q4: 可以添加多个从库吗?
可以! 修改配置即可:
read-data-source-names:
- slave
- slave-2 # 新增
🎯 进阶玩法
自定义SQL查询
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("SELECT * FROM user WHERE email = #{email}")
User findByEmail(@Param("email") String email);
}
分页查询
public IPage<User> pageQuery(int current, int size) {
Page<User> page = new Page<>(current, size);
return this.page(page);
}
逻辑删除
@TableLogic
private Integer deleted; // 0-未删除 1-已删除
📊 生产环境注意事项
方面 建议 安全性 使用 Jasypt 加密密码,禁用明文配置 连接池 调优 HikariCP 参数 监控 集成 Prometheus + Grafana 备份 定期备份并验证恢复 故障转移 使用 MHA 或 Orchestrator 延迟监控 监控 Seconds_Behind_Master
🌟 总结
通过本项目,你学会了:
✅ 独立搭建 MySQL 主从环境
✅ 配置 ShardingSphere-JDBC 实现读写分离
✅ 使用 MyBatis-Plus 高效开发
✅ 验证读写分离功能正确性
✅ 扩展为多从库架构
📚 参考资源
⭐ 如果对你有帮助
别忘了点个 Star ⭐ 支持一下!
你的支持是我持续更新的动力 💪
感谢阅读!如有问题欢迎留言讨论 😊
📬 更多实战干货
三年全栈经验持续输出 可复用代码 · 踩坑记录 · 成长心得
👋 全平台关注,一起成长
📬 绿泡泡:it全栈小屋
🔗 代码获取:https://gitee.com/xiaohelikesleep
🔗 CSDN:https://blog.csdn.net/interest_ing_
🔗 掘金:https://juejin.cn/user/3556246962047559
用代码记录成长,用分享对抗遗忘
感谢阅读,我们下篇见 👋