当前位置: 首页 > java >正文

Spring Boot主从数据库完全教程 - 从零到精通

目录

1. 前言 - 为什么要学习主从分离

第一章:主从数据库基础知识

1.1 什么是主从数据库

1.2 主从复制的原理

1.3 主从分离的优势

1.4 应用场景分析

第二章:环境搭建与准备

2.1 软件环境要求

2.2 MySQL主从环境搭建

2.2.1 准备两个MySQL实例

2.2.2 配置主库(Master)

2.2.3 配置从库(Slave)

2.3 测试主从同步

2.4 常见问题排查

问题1:Slave_IO_Running 显示 No

问题2:Slave_SQL_Running 显示 No

问题3:主从数据不一致

第三章:Spring Boot项目初始化

3.1 创建项目

方式一:使用Spring Initializr(推荐)

方式二:使用IDEA创建

3.2 依赖配置详解

3.3 项目结构设计

第四章:主从分离核心配置

4.1 数据源配置详解

4.2 动态数据源原理

4.2.1 核心原理解析

4.2.2 @DS注解原理

4.3 连接池优化配置

4.3.1 Druid连接池参数详解

4.3.2 连接池大小计算公式

第五章:代码实战开发

5.1 数据库表设计

5.2 实体类开发

5.2.1 基础实体类

5.2.2 用户实体类

5.2.3 订单实体类

5.3 Mapper层开发

5.3.1 用户Mapper

5.4 Service层开发(重点)

5.4.1 用户Service接口

5.4.2 用户Service实现(核心)

5.4.3 订单Service实现

5.5 Controller层开发

5.5.1 统一响应类

5.5.2 用户Controller

5.6 统一响应处理

5.6.1 全局异常处理

第六章:高级特性实现

6.1 自动路由实现

6.2 多从库负载均衡

6.2.1 配置多个从库

6.2.2 自定义负载均衡策略

6.3 读写分离事务处理

6.3.1 事务传播行为配置

6.3.2 复杂事务场景处理

6.4 主从延迟解决方案

6.4.1 延迟监控

6.4.2 延迟处理策略

第七章:监控与运维

7.1 Druid监控配置

7.1.1 Druid监控页面配置

7.1.2 自定义监控指标

7.2 主从状态监控

7.2.1 完整的主从监控服务

7.2.2 监控接口

7.3 性能监控与优化

7.3.1 SQL执行监控

7.4 日志配置与分析

7.4.1 日志配置文件

7.4.2 日志分析工具

第八章:实战案例

8.1 用户管理系统


1. 前言 - 为什么要学习主从分离

想象一下,你经营着一家很火的餐厅:

  • 只有一个厨师(单数据库):既要做菜又要配菜,忙不过来
  • 请了帮厨(主从分离):主厨专心炒菜(写数据),帮厨负责配菜装盘(读数据)

在实际项目中,当你的网站用户量增长后,数据库往往会成为性能瓶颈。通过主从分离,我们可以:

  • 让网站响应更快(查询走从库,分担压力)
  • 提高数据安全性(从库是天然的备份)
  • 实现高可用(主库挂了,从库可以顶上)

本教程将手把手教你实现Spring Boot的主从分离,让你的项目性能提升50%以上!


第一章:主从数据库基础知识

1.1 什么是主从数据库

主从数据库是一种数据库架构模式,就像公司的组织结构:

                    用户请求↓应用程序(Spring Boot)↙    ↘写操作    读操作↓         ↓主数据库    从数据库(Master)     (Slave)↓         ↑└─→ 数据同步 ←┘

通俗解释

  • 主库(Master):老板,负责"发号施令"(处理写操作)
  • 从库(Slave):员工,负责"执行查询"(处理读操作)
  • 数据同步:老板的决定会自动通知给所有员工

1.2 主从复制的原理

MySQL主从复制的过程就像"传话游戏":

主库:我要记录一条数据 → 写入Binary Log(二进制日志)↓
从库:我来看看主库有什么新动作 → 读取Binary Log↓
从库:收到,我也记录一下 → 写入Relay Log(中继日志)↓
从库:执行同样的操作 → 数据保持一致

详细步骤

  1. 主库记录变更:所有的INSERT、UPDATE、DELETE操作都会记录到Binary Log
  2. 从库IO线程:连接主库,读取Binary Log内容
  3. 从库写入中继日志:将读取的内容写入本地的Relay Log
  4. 从库SQL线程:读取Relay Log,执行相应的SQL语句

1.3 主从分离的优势

  1. 性能提升

    • 读写分离,互不干扰
    • 可以使用不同的索引策略(主库面向写优化,从库面向读优化)
  2. 高可用性

    • 主库故障时,从库可以快速切换为主库
    • 实现零停机维护
  3. 扩展性强

    • 可以增加多个从库分担读压力
    • 支持地理分布式部署
  4. 数据备份

    • 从库就是实时的数据备份
    • 可以在从库上进行备份操作,不影响主库性能

1.4 应用场景分析

适合使用主从分离的场景

  • 读多写少的应用(如新闻网站、博客系统)
  • 报表查询系统(复杂查询不影响主业务)
  • 需要实时备份的关键业务

不适合的场景

  • 写操作非常频繁的系统
  • 对数据一致性要求极高的金融交易系统
  • 小型应用(增加复杂度但收益不大)

第二章:环境搭建与准备

2.1 软件环境要求

在开始之前,请确保你的电脑上已安装以下软件:

软件版本要求说明
JDK8+推荐使用JDK 11
Maven3.6+项目构建工具
MySQL5.7+数据库服务器
IDEA2020+推荐的开发工具
Postman最新版API测试工具

2.2 MySQL主从环境搭建

2.2.1 准备两个MySQL实例

方案一:使用Docker(推荐新手)

# 创建Docker网络
docker network create mysql-network# 启动主库(端口3306)
docker run -d \--name mysql-master \--network mysql-network \-p 3306:3306 \-e MYSQL_ROOT_PASSWORD=123456 \-e MYSQL_DATABASE=test_db \mysql:5.7# 启动从库(端口3307)
docker run -d \--name mysql-slave \--network mysql-network \-p 3307:3306 \-e MYSQL_ROOT_PASSWORD=123456 \-e MYSQL_DATABASE=test_db \mysql:5.7

方案二:本地安装多实例 如果你已经有MySQL,可以通过修改配置文件创建多实例。

2.2.2 配置主库(Master)
  1. 进入主库
# Docker方式
docker exec -it mysql-master mysql -uroot -p123456# 本地方式
mysql -h127.0.0.1 -P3306 -uroot -p123456
  1. 修改主库配置
# Docker方式:先进入容器
docker exec -it mysql-master bash
echo "[mysqld]
server-id=1
log-bin=mysql-bin
binlog-format=ROW
binlog-do-db=test_db" >> /etc/mysql/mysql.conf.d/mysqld.cnf
  1. 创建同步账号
-- 创建用于同步的账号
CREATE USER 'slave_user'@'%' IDENTIFIED BY 'slave_pass';-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'%';-- 刷新权限
FLUSH PRIVILEGES;-- 查看主库状态(记住File和Position的值)
SHOW MASTER STATUS;

输出示例:

+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      154 | test_db      |                  |
+------------------+----------+--------------+------------------+
2.2.3 配置从库(Slave)
  1. 进入从库
# Docker方式
docker exec -it mysql-slave mysql -uroot -p123456# 本地方式
mysql -h127.0.0.1 -P3307 -uroot -p123456
  1. 修改从库配置
# Docker方式:先进入容器
docker exec -it mysql-slave bash
echo "[mysqld]
server-id=2
relay-log=slave-relay-bin
read_only=1" >> /etc/mysql/mysql.conf.d/mysqld.cnf
  1. 配置主从同步
-- 停止从库(如果正在运行)
STOP SLAVE;-- 配置主库信息(注意修改为你的实际值)
CHANGE MASTER TOMASTER_HOST='mysql-master',  -- Docker用容器名,本地用IPMASTER_PORT=3306,MASTER_USER='slave_user',MASTER_PASSWORD='slave_pass',MASTER_LOG_FILE='mysql-bin.000001',  -- 从SHOW MASTER STATUS获取MASTER_LOG_POS=154;                   -- 从SHOW MASTER STATUS获取-- 启动从库
START SLAVE;-- 查看从库状态
SHOW SLAVE STATUS\G;

2.3 测试主从同步

  1. 在主库创建测试表
-- 在主库执行
USE test_db;CREATE TABLE test_sync (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);INSERT INTO test_sync (name) VALUES ('测试数据1'), ('测试数据2');
  1. 在从库验证
-- 在从库执行
USE test_db;-- 查看表是否同步
SHOW TABLES;-- 查看数据是否同步
SELECT * FROM test_sync;

如果能看到相同的数据,说明主从同步成功!

2.4 常见问题排查

问题1:Slave_IO_Running 显示 No
-- 1. 检查网络连接
-- 在从库上测试是否能连接主库
mysql -h主库IP -P3306 -uslave_user -pslave_pass-- 2. 检查防火墙
-- 确保3306端口开放-- 3. 检查Binary Log是否开启
-- 在主库执行
SHOW VARIABLES LIKE 'log_bin';
问题2:Slave_SQL_Running 显示 No
-- 1. 查看错误信息
SHOW SLAVE STATUS\G;
-- 找到 Last_SQL_Error 字段-- 2. 跳过错误(慎用)
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE;
问题3:主从数据不一致
# 重新同步(会清空从库数据)
# 1. 在主库导出数据
mysqldump -h127.0.0.1 -P3306 -uroot -p123456 test_db > master_backup.sql# 2. 在从库导入
mysql -h127.0.0.1 -P3307 -uroot -p123456 test_db < master_backup.sql# 3. 重新配置主从同步

第三章:Spring Boot项目初始化

3.1 创建项目

方式一:使用Spring Initializr(推荐)
  1. 访问 https://start.spring.io/

  2. 填写项目信息:

    • Project: Maven
    • Language: Java
    • Spring Boot: 2.7.x 或 3.x
    • Group: com.example
    • Artifact: master-slave-demo
    • Packaging: Jar
    • Java: 11
  3. 添加依赖:

    • Spring Web
    • MySQL Driver
    • Lombok
  4. 点击"Generate"下载项目

方式二:使用IDEA创建
  1. File → New → Project
  2. 选择Spring Initializr
  3. 填写项目信息(同上)
  4. 选择依赖(同上)
  5. 完成创建

3.2 依赖配置详解

打开pom.xml,添加完整的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/></parent><groupId>com.example</groupId><artifactId>master-slave-demo</artifactId><version>1.0.0</version><name>master-slave-demo</name><description>Spring Boot主从分离示例项目</description><properties><java.version>11</java.version><mybatis-plus.version>3.5.3.1</mybatis-plus.version><dynamic-datasource.version>3.6.1</dynamic-datasource.version><druid.version>1.2.16</druid.version></properties><dependencies><!-- Spring Boot核心依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- MyBatis Plus:简化MyBatis操作 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!-- 动态数据源:实现主从切换的核心 --><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>${dynamic-datasource.version}</version></dependency><!-- Druid连接池:阿里巴巴的数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><!-- Lombok:简化实体类 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- Validation:参数校验 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!-- AOP:切面编程 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- API文档 --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>1.6.14</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

3.3 项目结构设计

创建标准的分层架构:

master-slave-demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/masterslave/
│   │   │       ├── config/              # 配置类
│   │   │       │   ├── DataSourceConfig.java
│   │   │       │   ├── DruidConfig.java
│   │   │       │   └── MyBatisPlusConfig.java
│   │   │       ├── controller/          # 控制器层
│   │   │       │   ├── UserController.java
│   │   │       │   └── OrderController.java
│   │   │       ├── entity/              # 实体类
│   │   │       │   ├── User.java
│   │   │       │   ├── Order.java
│   │   │       │   └── BaseEntity.java
│   │   │       ├── mapper/              # Mapper接口
│   │   │       │   ├── UserMapper.java
│   │   │       │   └── OrderMapper.java
│   │   │       ├── service/             # 服务层
│   │   │       │   ├── UserService.java
│   │   │       │   ├── OrderService.java
│   │   │       │   └── impl/
│   │   │       │       ├── UserServiceImpl.java
│   │   │       │       └── OrderServiceImpl.java
│   │   │       ├── aspect/              # 切面类
│   │   │       │   └── DataSourceAspect.java
│   │   │       ├── monitor/             # 监控类
│   │   │       │   └── SlaveMonitor.java
│   │   │       ├── common/              # 公共类
│   │   │       │   ├── Result.java     # 统一响应
│   │   │       │   ├── Constants.java  # 常量
│   │   │       │   └── GlobalExceptionHandler.java
│   │   │       └── MasterSlaveApplication.java  # 启动类
│   │   └── resources/
│   │       ├── application.yml          # 主配置文件
│   │       ├── application-dev.yml      # 开发环境
│   │       ├── application-prod.yml     # 生产环境
│   │       ├── mapper/                  # MyBatis XML文件
│   │       │   ├── UserMapper.xml
│   │       │   └── OrderMapper.xml
│   │       ├── db/                      # 数据库脚本
│   │       │   └── init.sql
│   │       └── logback-spring.xml       # 日志配置
│   └── test/                            # 测试代码
│       └── java/
│           └── com/example/masterslave/
│               ├── service/
│               └── MasterSlaveApplicationTests.java
├── .gitignore
├── README.md
└── pom.xml

第四章:主从分离核心配置

4.1 数据源配置详解

创建application.yml配置文件:

# 服务器配置
server:port: 8080servlet:context-path: /api# Spring配置
spring:application:name: master-slave-demo# 多数据源配置(最重要的部分)datasource:dynamic:# 设置默认的数据源组,默认为masterprimary: master# 严格匹配数据源,默认false,建议生产环境设为truestrict: true# 数据源切换的AOP顺序,默认2147483640order: 1# 数据源配置datasource:# 主库配置master:# 数据库连接信息url: jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver# 连接池配置(使用Druid)type: com.alibaba.druid.pool.DruidDataSourcedruid:# 初始化连接数initial-size: 5# 最小空闲连接数min-idle: 5# 最大活动连接数max-active: 20# 获取连接最大等待时间(毫秒)max-wait: 60000# 检测空闲连接的时间间隔(毫秒)time-between-eviction-runs-millis: 60000# 连接最小生存时间(毫秒)min-evictable-idle-time-millis: 300000# 用于检测连接是否有效的SQLvalidation-query: SELECT 1# 空闲时是否检测连接test-while-idle: true# 获取连接时是否检测test-on-borrow: false# 归还连接时是否检测test-on-return: false# 是否缓存preparedStatementpool-prepared-statements: true# 最大PSCache数量max-pool-prepared-statement-per-connection-size: 20# 监控统计拦截的filtersfilters: stat,wall,slf4j# 通过connectProperties属性来打开mergeSql功能connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000# 从库配置(第一个从库)slave_1:url: jdbc:mysql://localhost:3307/test_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 5min-idle: 5max-active: 20max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000validation-query: SELECT 1test-while-idle: truetest-on-borrow: falsetest-on-return: false# 从库配置(第二个从库,可选)slave_2:url: jdbc:mysql://localhost:3308/test_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 5min-idle: 5max-active: 20max-wait: 60000# MyBatis Plus配置
mybatis-plus:# mapper文件位置mapper-locations: classpath*:/mapper/**/*.xml# 实体类包路径type-aliases-package: com.example.masterslave.entity# 全局配置global-config:# 数据库配置db-config:# 主键策略id-type: auto# 逻辑删除字段logic-delete-field: deleted# 逻辑删除值logic-delete-value: 1# 逻辑未删除值logic-not-delete-value: 0# 配置configuration:# 驼峰命名map-underscore-to-camel-case: true# 缓存cache-enabled: false# 日志(开发环境建议开启)log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 日志配置
logging:level:# 显示SQL日志com.example.masterslave.mapper: debug# 显示数据源切换日志com.baomidou.dynamic: debug

4.2 动态数据源原理

4.2.1 核心原理解析

动态数据源的核心是通过ThreadLocal保存当前线程使用的数据源标识:

@Component
public class DynamicDataSourceContextHolder {// 使用ThreadLocal保存数据源标识private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();// 设置数据源public static void setDataSource(String dataSource) {CONTEXT_HOLDER.set(dataSource);}// 获取数据源public static String getDataSource() {return CONTEXT_HOLDER.get();}// 清除数据源public static void clearDataSource() {CONTEXT_HOLDER.remove();}
}
4.2.2 @DS注解原理

@DS注解通过AOP拦截方法调用,动态切换数据源:

// 使用示例
@Service
public class UserService {@DS("master")  // 使用主库public void saveUser(User user) {// 保存用户}@DS("slave")   // 使用从库public User getUser(Long id) {// 查询用户}
}

4.3 连接池优化配置

4.3.1 Druid连
http://www.xdnf.cn/news/15068.html

相关文章:

  • ubuntu22默认安装firefox使用snap安装还老打不开解决办法
  • Unity Demo——3D平台跳跃游戏笔记
  • IDE 关联 Git 操作
  • Flutter、Vue 3 和 React 在 UI 布局比较
  • windows下安装 redis
  • 代账行业数字化破局:从“知道”到“做到”,三步走稳赢!
  • 【Java】【力扣】102.二叉树层序遍历
  • 【TCP/IP】18. 因特网服务质量
  • PyTorch 与 Spring AI 集成实战
  • 【操作系统】线程
  • vue3 el-input 通过数组 获取显示
  • docker 启动中间件
  • LeetCode 148 排序链表解析:高效归并排序实现
  • 搭建渗透测试环境
  • React之旅-05 List Key
  • 力扣 hot100 Day40
  • Java 大视界 -- Java 大数据在智能交通智能停车诱导与车位共享中的应用(341)
  • AI翻唱——So-VITS-SVC
  • mvn能只test单独一个文件吗
  • 攻防世界——web题catcat-new session值伪造
  • 电脑息屏工具,一键黑屏超方便
  • 【LeetCode100】--- 1.两数之和【复习回滚】
  • 学习日记-spring-day45-7.10
  • 深入理解 Linux 中的 stat 函数与文件属性操作
  • 710 Mybatis实战
  • Using Spring for Apache Pulsar:Transactions
  • PyTorch Tensor 操作入门:转换、运算、维度变换
  • 【TCP/IP】11. IP 组播
  • 深入解析JVM内存结构与垃圾回收机制
  • Boost.Asio学习(3):异步读写