springboot + mybatis-plus 分包实现多数据源配置
2020年6月21日大约 4 分钟
业务背景
同一个应用需要访问多个数据源,比如读写分离,或者需要对不同的库做 ETL 之类的。
那么如何配置多数据源呢?
文本就 mybatis 和 mybatis-plus 提供配置的基础案例。
实现方式
多数据源可以采用分包,或者通过 aop+注解的方式实现。
整体的配置
使用 springboot 做个案例。
maven 配置
对应的 maven 配置如下:
4.0.0
mp-sb-mluti
org.springframework.boot
spring-boot-starter-parent
2.1.6.RELEASE
3.4.4
1.3.1
2.3
1.8
org.springframework.boot
spring-boot-starter-jdbc
org.mybatis
mybatis
${mybatis.version}
org.mybatis
mybatis-spring
${mybatis-spring.version}
com.baomidou
mybatis-plus
${mybatis-plus.version}
mybatis
org.mybatis
mybatis-spring
org.mybatis
mysql
mysql-connector-java
runtime
com.oracle
ojdbc6
11.2.0.3
com.alibaba
druid-spring-boot-starter
1.1.14
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.apache.velocity
velocity-engine-core
2.0
org.springframework.boot
spring-boot-configuration-processor
true
目录结构
├─java
│ └─dal
│ │ Application.java
│ │
│ ├─config
│ │ MainDataSourceConfig.java
│ │ SecondDataSourceConfig.java
│ │
│ ├─entity
│ │ ├─main
│ │ │ MainModel.java
│ │ │
│ │ └─second
│ │ SecondModel.java
│ │
│ ├─mapper
│ │ ├─main
│ │ │ MainMapper.java
│ │ │
│ │ └─second
│ │ SecondMapper.java
│ │
│ └─service
│ ├─main
│ │ │ MainService.java
│ │ │
│ │ └─impl
│ │ MainServiceImpl.java
│ │
│ └─second
│ │ SecondService.java
│ │
│ └─impl
│ SecondServiceImpl.java
│
└─resources
│ application.properties
│
└─dal.mapper
│ README
│
├─main
│ MainMapper.xml
│
└─second
SecondMapper.xml
main 方法
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
mybatis 配置单数据源
代码生成
- generatorConfig.xml
对应的 mybatis-plus 数据源配置
- MainDataSourceConfig.java
package dal.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "dal.mapper.main", sqlSessionFactoryRef = "mainSqlSessionFactory")
public class MainDataSourceConfig {
@Bean("mainSqlSessionTemplate")
public SqlSessionTemplate mainSqlSessionTemplate(
@Qualifier("mainSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean("mainSqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("mainDataSource") DataSource dataSource,@Qualifier("mainPaginationInterceptor") PaginationInterceptor paginationInterceptor) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:dal/mapper/main/*.xml"));
Interceptor[] plugins = new Interceptor[]{paginationInterceptor};
sqlSessionFactoryBean.setPlugins(plugins);
return sqlSessionFactoryBean.getObject();
}
@Bean("mainPaginationInterceptor")
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean("mainDataSource")
public DataSource mainDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
druidDataSource.setUrl("jdbc:oracle:thin:@//ip:port/db");
druidDataSource.setUsername("name");
druidDataSource.setPassword("password");
return druidDataSource;
}
}
mybatis 的配置
二者最核心的区别就在于 sqlSessionFactory 方法,mybatis 直接使用 SqlSessionFactoryBean 替换掉 MybatisSqlSessionFactoryBean。
@Bean("mainSqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("mainDataSource") DataSource dataSource,@Qualifier("mainPaginationInterceptor")PaginationInterceptor paginationInterceptor) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:dal/mapper/main/*.xml"));
Interceptor[] plugins = new Interceptor[]{paginationInterceptor};
sqlSessionFactoryBean.setPlugins(plugins);
return sqlSessionFactoryBean.getObject();
}
mybatis 配置多数据源-分包
其实如果使用分包的话,实现起来非常简单。
就是 entity/mapper/xml 都放在独立的包中,然后扫包的时候独立即可。
mybatis-plus 例子
package dal.config;
/**
*
* https://blog.csdn.net/qq_36134369/article/details/95036273
*
* @author binbin.hou
* @since 1.0.0
*/
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "dal.mapper.second", sqlSessionFactoryRef = "secondSqlSessionFactory")
public class SecondDataSourceConfig {
@Bean("secondSqlSessionTemplate")
public SqlSessionTemplate secondSqlSessionTemplate(
@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean("secondSqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource,@Qualifier("secondPaginationInterceptor") PaginationInterceptor paginationInterceptor) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:dal/mapper/second/*.xml"));
Interceptor[] plugins = new Interceptor[]{paginationInterceptor};
sqlSessionFactoryBean.setPlugins(plugins);
return sqlSessionFactoryBean.getObject();
}
@Bean("secondPaginationInterceptor")
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean("secondDataSource")
public DataSource secondDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
druidDataSource.setUrl("jdbc:oracle:thin:@ip2:port2/db2");
druidDataSource.setUsername("name");
druidDataSource.setPassword("password");
return druidDataSource;
}
}
注意:所有的插件,mybatis 配置都做要彻底隔离。
我在测试过程中为了复用,一开始将分页插件,全局配置等设置为公用,后来发现会导致数据源的混乱。
参考资料
项目模板丨多数据源搭建 maven+spring-boot+druid+mybatis-plus+分页插件+分包
贡献者
binbin.hou