引言
在高并发场景下,单一数据库实例往往成为性能瓶颈。数据库读写分离通过将读操作和写操作分配到不同的数据库实例,有效缓解主库压力,提升系统吞吐量。MyBatis-Plus 作为一款强大的持久层框架,结合 Spring Boot 能够轻松实现读写分离。
一、读写分离的核心价值与挑战
1.1 高并发场景下的性能瓶颈
传统单库架构在QPS突破10万时,常面临以下问题:
-
写入阻塞:大量INSERT/UPDATE操作导致锁竞争
-
查询延迟:复杂报表分析占用CPU资源
-
扩展困难:垂直扩容成本呈指数级增长
二、读写分离核心原理
2.1 基本概念
主库(Master):负责处理所有写操作(INSERT/UPDATE/DELETE),保证数据一致性
从库(Slave):负责处理读操作(SELECT),支持水平扩展
核心目标:通过主从复制保证数据同步,通过数据源路由实现读写分离
2.2 关键技术点
数据源路由:根据操作类型(读 / 写)动态切换数据源
主从复制:通过数据库自身机制(如 MySQL 的 Binlog 复制)保证主从数据一致
事务处理:写操作必须在主库执行,读操作可路由到从库
三、Spring Boot集成实战
3.1 环境搭建
Maven核心依赖:
java
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.2</version>
</dependency>
3.2 数据源配置
java
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://master-host:3306/core?useSSL=false
username: admin
password: master@123
driver-class-name: com.mysql.cj.jdbc.Driver
slave1:
url: jdbc:mysql://slave1-host:3306/core?useSSL=false
username: readonly
password: slave@123
driver-class-name: com.mysql.cj.jdbc.Driver
slave2:
url: jdbc:mysql://slave2-host:3306/core?useSSL=false
username: readonly
password: slave@123
driver-class-name: com.mysql.cj.jdbc.Driver
3.3 业务层实现
java
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> {
// 写操作自动路由到主库
@Override
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
baseMapper.insert(order);
}
// 读操作指定从库
@Override
@DS("slave")
public Order getOrderById(Long id) {
return baseMapper.selectById(id);
}
// 负载均衡读库
@DS("#slave")
public List<Order> listOrders() {
return baseMapper.selectList(null);
}
}
3.4 配置动态数据源
java
import com.baomidou.dynamic.datasource.processor.DynamicDataSourceProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
@Configuration
public class DataSourceConfig {
@Bean
@ConditionalOnMissingBean
public DynamicDataSourceProcessor dynamicDataSourceProcessor() {
return new DynamicDataSourceProcessor();
}
// 配置事务管理器(主库事务)
@Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager();
}
}
四、高阶功能实现
4.1 事务一致性保障
java
@DS("master") // 强制走主库
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(StockDTO dto) {
stockMapper.deduct(dto);
// 写入操作日志
logMapper.insert(dto.getLog());
}
关键机制:
主库事务管理器优先
跨数据源事务需引入Seata等分布式事务框架
4.2 读写分离+分库分表
java
dynamic:
sharding:
order:
actualDataNodes: master.order_$->{0..9},slave1.order_$->{0..9}
tableStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: mod10
结合分片算法实现水平扩展
五、生产级优化策略
5.1 连接池配置
java
spring:
datasource:
dynamic:
hikari:
maxPoolSize: 50
minIdle: 10
connectionTimeout: 30000
idleTimeout: 600000
maxLifetime: 1800000
调优建议:
根据QPS计算连接数:maxPoolSize = (QPS × avg_query_time) / 1000
启用监控:集成Druid监控面板
5.2 数据同步监控
java
@Scheduled(fixedRate = 60000)
public void checkReplicationDelay() {
Long delay = slaveMapper.getReplicationDelay();
if (delay > 5000) {
alertService.send("从库延迟超过5秒!");
}
}
5.3 故障转移机制
java
@Bean
public MasterSlaveAutoRoutingPlugin routingPlugin() {
MasterSlaveAutoRoutingPlugin plugin = new MasterSlaveAutoRoutingPlugin();
plugin.setHealthCheckInterval(30000); // 30秒健康检查
plugin.setSlaveRetryTimes(3); // 从库失败重试次数
return plugin;
}
总结
通过 MyBatis-Plus 实现数据库读写分离,能够显著提升系统的读性能和可用性,是高并发场景下的必备技术。核心优势包括:
低侵入性:通过注解轻松实现数据源切换
灵活扩展:支持多从库负载均衡和动态数据源配置
事务安全:确保写操作在主库执行,保障数据一致性