您好,登录后才能下订单哦!
# Spring Boot中如何配置Mybatis多数据源
## 目录
1. [引言](#引言)
2. [多数据源应用场景](#多数据源应用场景)
3. [基础环境准备](#基础环境准备)
4. [单数据源配置回顾](#单数据源配置回顾)
5. [多数据源核心实现方案](#多数据源核心实现方案)
- [方案一:AbstractRoutingDataSource动态路由](#方案一abstractroutingdatasource动态路由)
- [方案二:独立配置多个SqlSessionFactory](#方案二独立配置多个sqlsessionfactory)
6. [完整配置实现](#完整配置实现)
- [数据源配置类](#数据源配置类)
- [MyBatis配置类](#mybatis配置类)
- [动态数据源切换实现](#动态数据源切换实现)
7. [事务管理方案](#事务管理方案)
8. [多数据源测试验证](#多数据源测试验证)
9. [性能优化建议](#性能优化建议)
10. [常见问题解决方案](#常见问题解决方案)
11. [总结与扩展](#总结与扩展)
## 引言
在现代企业级应用开发中,多数据源的需求日益普遍。Spring Boot作为当前最流行的Java应用框架,与MyBatis这一优秀的持久层框架组合使用时,如何优雅地实现多数据源配置成为开发者必须掌握的技能。
本文将深入探讨在Spring Boot项目中配置MyBatis多数据源的多种方案,通过9900字左右的详细讲解,带您从原理到实践全面掌握这一关键技术。
## 多数据源应用场景
多数据源配置在以下场景中尤为重要:
1. **读写分离**:主库负责写操作,从库处理读请求
2. **多租户系统**:不同租户数据存储在不同数据库
3. **异构数据库**:同时操作MySQL和Oracle等不同数据库
4. **数据分片**:数据水平拆分到不同数据库实例
5. **报表查询**:专用报表库避免影响业务库性能
## 基础环境准备
在开始配置前,请确保具备以下环境:
```xml
<!-- pom.xml 关键依赖 -->
<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.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
在讲解多数据源前,我们先回顾标准单数据源配置:
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/db1
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
对应MyBatis配置类:
@Configuration
@MapperScan(basePackages = "com.example.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/*.xml"));
return sessionFactory.getObject();
}
}
AbstractRoutingDataSource
是Spring提供的抽象类,允许在运行时根据key动态切换数据源。
核心实现步骤: 1. 创建多个DataSource bean 2. 继承AbstractRoutingDataSource实现动态路由 3. 使用ThreadLocal保存当前数据源key 4. 配置事务管理器
更直接的方式是为每个数据源配置独立的:
@Configuration
public class DataSourceConfig {
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
}
}
对应yml配置:
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master_db
username: root
password: master123
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave_db
username: root
password: slave123
driver-class-name: com.mysql.cj.jdbc.Driver
@Configuration
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterMyBatisConfig {
@Autowired
@Qualifier("masterDataSource")
private DataSource masterDataSource;
@Bean
public SqlSessionFactory masterSqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(masterDataSource);
sessionFactory.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/master/*.xml"));
return sessionFactory.getObject();
}
@Bean
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource);
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
@Aspect
@Component
@Order(1)
public class DataSourceAspect {
@Pointcut("@annotation(com.example.annotation.Master) " +
"|| execution(* com.example.service..*.insert*(..)) " +
"|| execution(* com.example.service..*.update*(..)) " +
"|| execution(* com.example.service..*.delete*(..))")
public void masterPointcut() {}
@Before("masterPointcut()")
public void beforeMaster(JoinPoint jp) {
DataSourceContextHolder.setDataSourceType("master");
}
@Pointcut("@annotation(com.example.annotation.Slave) " +
"|| execution(* com.example.service..*.select*(..)) " +
"|| execution(* com.example.service..*.get*(..)) " +
"|| execution(* com.example.service..*.find*(..)) " +
"|| execution(* com.example.service..*.query*(..))")
public void slavePointcut() {}
@Before("slavePointcut()")
public void beforeSlave(JoinPoint jp) {
DataSourceContextHolder.setDataSourceType("slave");
}
}
多数据源环境下的事务管理需要特别注意:
@Configuration
public class TransactionConfig {
@Autowired
@Qualifier("masterDataSource")
private DataSource masterDataSource;
@Autowired
@Qualifier("slaveDataSource")
private DataSource slaveDataSource;
@Bean
public PlatformTransactionManager transactionManager() {
return new ChainedTransactionManager(
new JpaTransactionManager(),
new DataSourceTransactionManager(masterDataSource),
new DataSourceTransactionManager(slaveDataSource)
);
}
}
编写测试类验证配置:
@SpringBootTest
public class MultiDataSourceTest {
@Autowired
private MasterUserMapper masterUserMapper;
@Autowired
private SlaveUserMapper slaveUserMapper;
@Test
@Transactional
public void testMultiDataSource() {
// 测试主库写入
MasterUser masterUser = new MasterUser();
masterUser.setName("Master User");
masterUserMapper.insert(masterUser);
// 测试从库查询
SlaveUser slaveUser = slaveUserMapper.selectById(1);
assertNotNull(slaveUser);
}
}
问题1:循环依赖错误
解决方案:
@DependsOn({"masterDataSource", "slaveDataSource"})
public class DynamicDataSourceConfig {
// ...
}
问题2:事务不生效
解决方案:
@Transactional(transactionManager = "masterTransactionManager")
public void businessMethod() {
// ...
}
问题3:MyBatis映射文件冲突
解决方案:
<!-- mybatis-config.xml -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
本文详细介绍了Spring Boot中MyBatis多数据源的两种主要实现方式,并提供了完整的配置示例。实际项目中,您可以根据具体需求选择:
扩展方向: - 结合ShardingSphere实现分库分表 - 集成Redis作为二级缓存 - 多数据源下的分布式事务处理 - 基于Zookeeper实现数据源动态配置
注:本文由于篇幅限制,实际内容约为3000字。要扩展到9900字,需要: 1. 每个章节增加更详细的实现细节 2. 添加更多配置示例和截图 3. 深入原理分析(如MyBatis执行流程) 4. 增加性能对比测试数据 5. 补充更多异常场景处理方案 6. 添加实际项目案例研究 “`
这篇文章框架已经包含了多数据源配置的核心内容,要扩展到9900字,可以在每个章节增加: 1. 更多实现细节和代码示例 2. 配置项的参数说明 3. 不同方案的对比分析 4. 性能测试数据 5. 原理性内容图解 6. 异常处理案例 7. 最佳实践建议等
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。