Spring+MyBatis实现数据库读写分离方案
一、方案背景与目标
在高并发业务场景中,数据库往往是系统性能的瓶颈,尤其是读操作频繁的业务(如电商商品查询、新闻资讯浏览等)。单一数据库节点无法承载大量的并发读写请求,容易出现响应延迟、连接溢出等问题。
数据库读写分离方案通过将写操作(INSERT、UPDATE、DELETE)路由至主数据库,读操作(SELECT)分发至多个从数据库,结合数据库主从复制机制保证数据一致性,从而实现以下目标:
-
提升并发处理能力:分散读请求到多个从库,降低主库压力,提高整体吞吐量
-
提高数据可用性:主库故障时可快速切换,从库可继续提供读服务
-
优化性能体验:可根据业务需求部署从库至不同地域,降低读请求延迟
-
简化扩展成本:新增读节点无需修改核心业务逻辑,支持水平扩展
二、核心原理
2.1 主从复制机制
基于MySQL等数据库的主从复制功能,实现主库数据向从库的异步同步,是读写分离的基础。其核心流程如下:
-
主库执行写操作后,将操作记录写入二进制日志(binlog)
-
从库启动IO线程,连接主库并读取binlog内容,保存至本地中继日志(relaylog)
-
从库启动SQL线程,解析中继日志并执行相同操作,实现与主库数据同步
注意:主从复制存在微小延迟(通常毫秒级),需结合业务场景设计延迟容忍策略
2.2 读写路由机制
通过Spring提供的数据源扩展能力,自定义动态数据源路由策略,根据SQL操作类型(读/写)自动切换至对应数据库节点。核心组件包括:
-
动态数据源:继承Spring的AbstractRoutingDataSource,实现数据源路由逻辑
-
数据源上下文:通过ThreadLocal存储当前线程的数据源标识(主库/从库)
-
路由触发:通过注解或AOP切面,在执行SQL前设置数据源标识
三、环境准备
3.1 硬件与软件环境
| 组件 | 版本要求 | 说明 |
|---|---|---|
| JDK | 1.8及以上 | 支持Spring Boot最新稳定版 |
| Spring Boot | 2.x及以上 | 提供自动配置简化开发 |
| MyBatis | 3.5.x及以上 | 配合MyBatis-Spring-Boot-Starter整合 |
| MySQL | 5.7及以上 | 支持主从复制功能 |
| 数据库连接池 | HikariCP | Spring Boot默认连接池,性能优异 |
3.2 数据库主从配置(以MySQL为例)
3.2.1 主库配置(master)
修改MySQL配置文件my.cnf:
# 主库唯一标识
server-id=1
# 开启二进制日志
log-bin=mysql-bin
# 同步的数据库(可指定多个)
binlog-do-db=test_db
# 忽略同步的数据库
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
# 二进制日志格式(row格式支持全量数据同步)
binlog_format=ROW
# 防止主从同步延迟导致的主键冲突
auto-increment-offset=1
auto-increment-increment=2
3.2.2 从库配置(slave)
修改从库MySQL配置文件my.cnf:
# 从库唯一标识(与主库不同)
server-id=2
# 开启中继日志
relay-log=mysql-relay-bin
# 只读模式(仅对非超级用户生效)
read-only=1
# 忽略同步的数据库
replicate-ignore-db=mysql
replicate-ignore-db=information_schema
3.2.3 主从连接配置
-
主库创建同步账号并授权:
CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl@123456'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES; -
查看主库binlog状态:
SHOW MASTER STATUS; -- 记录File(如mysql-bin.000001)和Position(如154)值 -
从库配置主库信息并启动同步:
`CHANGE MASTER TO
MASTER_HOST=‘主库IP’,
MASTER_USER=‘repl’,
MASTER_PASSWORD=‘Repl@123456’,
MASTER_LOG_FILE=‘主库File值’,
MASTER_LOG_POS=主库Position值;
– 启动从库同步
START SLAVE;
– 查看同步状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes)
SHOW SLAVE STATUS\G;`
四、核心实现步骤
4.1 项目依赖配置(Maven)
在pom.xml中引入核心依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.10</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<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>
</dependencies>
4.2 配置文件编写(application.yml)
配置主从库数据源信息及MyBatis参数:
spring:
datasource:
# 主库数据源
master:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://主库IP:3306/test_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: Master@123456
# 从库数据源(可配置多个)
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://从库IP:3306/test_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: Slave@123456
# 连接池配置
hikari:
maximum-pool-size: 10
minimum-idle: 5
idle-timeout: 300000
connection-timeout: 20000
# MyBatis配置
mybatis:
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.example.demo.entity
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志
4.3 动态数据源核心实现
4.3.1 数据源类型枚举
定义数据源标识,区分主库和从库:
package com.example.demo.datasource;
public enum DataSourceType {
/**
* 主库
*/
MASTER,
/**
* 从库
*/
SLAVE
}
4.3.2 数据源上下文管理
通过ThreadLocal维护当前线程的数据源类型,保证线程安全:
(注:文档部分内容可能由 AI 生成)
1264

被折叠的 条评论
为什么被折叠?



