您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# tk-mybatis整合SpringBoot使用两个数据源的方法是什么
## 前言
在大型企业级应用开发中,多数据源配置是一个常见的需求场景。tk-mybatis作为MyBatis的增强工具,与SpringBoot的结合能够显著提升开发效率。本文将深入探讨如何在SpringBoot项目中整合tk-mybatis并配置双数据源,涵盖从原理到实践的完整解决方案。
## 目录
1. [多数据源应用场景分析](#一多数据源应用场景分析)
2. [环境准备与项目搭建](#二环境准备与项目搭建)
3. [基础单数据源配置](#三基础单数据源配置)
4. [双数据源完整实现方案](#四双数据源完整实现方案)
- 4.1 [AbstractRoutingDataSource原理](#41-abstractroutingdatasource原理)
- 4.2 [数据源配置类实现](#42-数据源配置类实现)
- 4.3 [动态数据源切换实现](#43-动态数据源切换实现)
5. [tk-mybatis多数据源适配](#五tk-mybatis多数据源适配)
6. [事务管理解决方案](#六事务管理解决方案)
7. [性能优化建议](#七性能优化建议)
8. [常见问题排查](#八常见问题排查)
9. [总结与扩展](#九总结与扩展)
---
## 一、多数据源应用场景分析
### 1.1 典型业务场景
- **主从读写分离**:主库负责写操作,从库处理读请求
- **多租户系统**:不同租户数据物理隔离
- **异构数据库整合**:MySQL与Oracle混合使用
- **分库分表场景**:数据水平拆分到不同库表
### 1.2 技术实现难点
1. 数据源动态切换机制
2. 事务一致性保证
3. 连接池资源管理
4. ORM框架兼容性
---
## 二、环境准备与项目搭建
### 2.1 技术栈版本
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
src/main/java
├── config
│ ├── DataSourceConfig.java
│ ├── MybatisConfig.java
├── datasource
│ ├── DynamicDataSource.java
│ ├── DataSourceContextHolder.java
├── mapper
│ ├── primary
│ └── secondary
spring:
datasource:
primary:
url: jdbc:mysql://localhost:3306/db1
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
@Configuration
@MapperScan(basePackages = "com.example.mapper.primary",
sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(primaryDataSource());
factory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/primary/*.xml"));
return factory.getObject();
}
}
Spring提供的抽象类,核心方法:
protected DataSource determineTargetDataSource() {
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
// ...
}
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("primary", primaryDataSource());
dataSourceMap.put("secondary", secondaryDataSource());
DynamicDataSource routingDataSource = new DynamicDataSource();
routingDataSource.setDefaultTargetDataSource(primaryDataSource());
routingDataSource.setTargetDataSources(dataSourceMap);
return routingDataSource;
}
}
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 type) {
contextHolder.set(type);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clear() {
contextHolder.remove();
}
}
@Configuration
@MapperScan(basePackages = "com.example.mapper.primary",
sqlSessionTemplateRef = "primarySqlSessionTemplate")
public class PrimaryMybatisConfig {
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(primaryDataSource());
}
@Bean(name = "primarySqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(primarySqlSessionFactory());
}
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "primary";
}
public class DataSourceAspect {
@Before("@annotation(ds)")
public void beforeSwitch(DataSource ds) {
DataSourceContextHolder.setDataSourceType(ds.value());
}
@After("@annotation(ds)")
public void afterSwitch() {
DataSourceContextHolder.clear();
}
}
方案 | 一致性 | 性能影响 | 实现复杂度 |
---|---|---|---|
JTA | 强一致 | 高 | 高 |
本地事务+最终一致 | 弱一致 | 低 | 中 |
Seata | 强一致 | 中 | 中高 |
@Service
public class UserService {
@Transactional(transactionManager = "primaryTransactionManager")
@DataSource("primary")
public void createPrimary(User user) {
// 主库操作
}
@DataSource("secondary")
public User getFromSecondary(Long id) {
// 从库查询
}
}
连接池配置:
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
MyBatis二级缓存:
<cache eviction="LRU" flushInterval="60000" size="1024"/>
SQL监控:
@Bean
public ServletRegistrationBean<StatViewServlet> druidServlet() {
return new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
}
问题1:循环依赖异常
解决方案:调整Bean加载顺序,使用@DependsOn
问题2:事务不生效
检查点:
1. 是否启用@EnableTransactionManagement
2. 方法是否为public
3. 异常类型是否匹配rollbackFor
本文详细介绍了SpringBoot+tk-mybatis多数据源整合方案,包含约7550字的技术内容。实际开发中应根据具体业务需求调整实现细节,建议在测试环境充分验证后再上线生产环境。 “`
注:由于篇幅限制,以上为精简后的文章框架和核心内容示例。完整7550字版本需要扩展每个章节的详细实现说明、原理图解、性能测试数据等内容。如需完整版本,可以告知具体需要重点扩展的章节。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。