Spring Boot + MySQL 主从复制实战指南

🧑‍💻 关于我

三年全栈实践 · Vue + Java 真实项目沉淀,可复用代码与踩坑解法

👋 关注我,收获实战经验,少走弯路

📬 绿泡泡:**it全栈小屋**

🔗 代码获取:https://gitee.com/xiaohelikesleep

🔗 CSDN:https://blog.csdn.net/interest_ing_

🔗 掘金:https://juejin.cn/user/3556246962047559

🔗 博客:https://blog.hfh.asia

🚀 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

🔗 博客:https://blog.hfh.asia

用代码记录成长,用分享对抗遗忘

感谢阅读,我们下篇见 👋