3步搞定MyBatis读写分离:Mapper动态数据源配置指南
3步搞定MyBatis读写分离:Mapper动态数据源配置指南
【免费下载链接】Mapper Mybatis Common Mapper - Easy to use 项目地址: https://gitcode.com/gh_mirrors/ma/Mapper
你还在为数据库读写分离配置复杂而烦恼吗?还在纠结如何优雅地整合动态数据源到MyBatis项目中?本文将通过3个简单步骤,带你快速实现基于MyBatis Common Mapper的动态数据源配置,轻松应对高并发场景下的数据库负载均衡。
读完本文你将获得:
- 掌握MyBatis Mapper多数据源配置核心方法
- 学会通过注解实现读写分离路由策略
- 获得可直接复用的动态数据源配置模板
- 了解生产环境下的最佳实践与常见问题
为什么需要读写分离?
在传统的单数据源架构中,所有数据库操作都通过一个数据库连接进行,这在高并发场景下会导致严重的性能瓶颈。读写分离架构通过将查询操作路由到从库,写操作路由到主库,可显著提升系统吞吐量。
MyBatis Common Mapper(以下简称Mapper)作为MyBatis的增强工具,提供了便捷的多数据源集成方案。通过MapperScannerConfigurer类的灵活配置,我们可以轻松实现数据源的动态切换。
核心组件与工作原理
读写分离架构图
关键技术组件
- 动态数据源路由:通过Spring的AbstractRoutingDataSource实现数据源动态选择
- Mapper多数据源支持:利用MapperScannerConfigurer的sqlSessionFactoryBeanName属性指定不同数据源
- 注解式事务管理:通过@Transactional注解指定事务使用的数据源
step 1: 配置多数据源
添加依赖
在pom.xml中添加Spring Boot和Mapper的依赖:
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
配置数据源信息
在application.properties中配置主从数据源:
# 主数据源配置
spring.datasource.master.url=jdbc:mysql://localhost:3306/master_db?useSSL=false
spring.datasource.master.username=root
spring.datasource.master.password=123456
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
# 从数据源配置
spring.datasource.slave1.url=jdbc:mysql://localhost:3306/slave1_db?useSSL=false
spring.datasource.slave1.username=root
spring.datasource.slave1.password=123456
spring.datasource.slave1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.slave2.url=jdbc:mysql://localhost:3306/slave2_db?useSSL=false
spring.datasource.slave2.username=root
spring.datasource.slave2.password=123456
spring.datasource.slave2.driver-class-name=com.mysql.cj.jdbc.Driver
# Mapper配置
mapper.mappers[0]=tk.mybatis.mapper.common.Mapper
mapper.notEmpty=true
mapper.style=uppercase
step 2: 实现动态数据源路由
创建数据源配置类
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave1")
public DataSource slave1DataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave2")
public DataSource slave2DataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource routingDataSource(@Qualifier("masterDataSource") DataSource master,
@Qualifier("slave1DataSource") DataSource slave1,
@Qualifier("slave2DataSource") DataSource slave2) {
Map<Object, Object> dataSources = new HashMap<>();
dataSources.put("master", master);
dataSources.put("slave1", slave1);
dataSources.put("slave2", slave2);
DynamicDataSource routingDataSource = new DynamicDataSource();
routingDataSource.setTargetDataSources(dataSources);
routingDataSource.setDefaultTargetDataSource(master);
return routingDataSource;
}
}
实现动态数据源路由类
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceKey(String key) {
contextHolder.set(key);
}
public static void clearDataSourceKey() {
contextHolder.remove();
}
@Override
protected Object determineCurrentLookupKey() {
return contextHolder.get();
}
}
step 3: 配置Mapper多数据源支持
配置SqlSessionFactory
@Configuration
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterMapperConfig {
@Bean
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("routingDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 设置主库Mapper扫描路径
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/master/*.xml"));
return sessionFactory.getObject();
}
}
@Configuration
@MapperScan(basePackages = "com.example.mapper.slave", sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveMapperConfig {
@Bean
public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("routingDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 设置从库Mapper扫描路径
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/slave/*.xml"));
return sessionFactory.getObject();
}
}
使用注解实现读写分离
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMasterMapper userMasterMapper;
@Autowired
private UserSlaveMapper userSlaveMapper;
@Override
@Transactional
public void createUser(User user) {
// 自动路由到主库
DynamicDataSource.setDataSourceKey("master");
userMasterMapper.insert(user);
DynamicDataSource.clearDataSourceKey();
}
@Override
public User getUserById(Long id) {
// 随机选择从库
String[] slaves = {"slave1", "slave2"};
DynamicDataSource.setDataSourceKey(slaves[new Random().nextInt(slaves.length)]);
User user = userSlaveMapper.selectByPrimaryKey(id);
DynamicDataSource.clearDataSourceKey();
return user;
}
}
最佳实践与注意事项
1. 事务管理
在使用读写分离时,需要特别注意事务边界。由于从库是主库的只读副本,写操作必须在主库上执行。可以通过Spring的事务注解指定数据源:
@Transactional(transactionManager = "masterTransactionManager")
2. 数据源切换策略
常见的数据源切换策略包括:
- 基于注解的手动切换
- 基于AOP的自动切换
- 基于负载均衡的从库选择
3. 延迟加载问题
在使用MyBatis的延迟加载功能时,需要确保延迟加载的属性访问也使用正确的数据源。可以通过MapperScannerConfigurer的lazyInitialization属性控制延迟加载行为。
4. 监控与运维
建议集成Spring Boot Actuator监控数据源状态:
management.endpoints.web.exposure.include=datasources,health
常见问题解决方案
1. 数据源切换不生效
检查是否正确配置了@MapperScan注解的sqlSessionFactoryRef属性,确保不同包下的Mapper使用不同的SqlSessionFactory。
2. 事务无法回滚
确保在事务方法中正确设置了数据源键,并且事务管理器与SqlSessionFactory对应。
3. 从库数据延迟
对于实时性要求高的业务,可以采用"写主读主"的策略,或者实现从库数据延迟检测机制。
总结与扩展
通过本文介绍的3个步骤,我们实现了基于MyBatis Common Mapper的动态数据源配置,主要包括:
- 配置多数据源连接信息
- 实现动态数据源路由
- 配置Mapper多数据源支持
这种方案的优势在于:
- 实现简单,无需复杂的第三方依赖
- 灵活性高,可根据业务需求自定义路由策略
- 与Spring生态深度整合,支持事务管理
对于更复杂的场景,可以考虑结合dynamic-datasource-spring-boot-starter等成熟框架,进一步简化多数据源配置。
官方文档:README.md Spring集成指南:spring/README.md Spring Boot集成示例:spring-boot-starter/mapper-spring-boot-samples
希望本文能帮助你轻松应对数据库读写分离的挑战,构建高性能的MyBatis应用!如果你有任何问题或建议,欢迎在评论区留言讨论。
【免费下载链接】Mapper Mybatis Common Mapper - Easy to use 项目地址: https://gitcode.com/gh_mirrors/ma/Mapper
更多推荐

所有评论(0)