业务背景
同一个应用需要访问多个数据源,比如读写分离,或者需要对不同的库做 ETL 之类的。
那么如何配置多数据源呢?
文本就 mybatis 和 mybatis-plus 提供配置的基础案例。
实现方式
多数据源可以采用分包,或者通过 aop+注解的方式实现。
整体的配置
使用 springboot 做个案例。
maven 配置
对应的 maven 配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>mp-sb-mluti</artifactId>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<mybatis.version>3.4.4</mybatis.version>
<mybatis-spring.version>1.3.1</mybatis-spring.version>
<mybatis-plus.version>2.3</mybatis-plus.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mybatis-plus-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatis-plus.version}</version>
<exclusions>
<exclusion>
<artifactId>mybatis</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
<exclusion>
<artifactId>mybatis-spring</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis-plus自动化工具需要的依赖 模板-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
目录结构
├─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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://www.mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<context id="context1" targetRuntime="MyBatis3"
defaultModelType="flat">
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<jdbcConnection driverClass="驱动"
connectionURL="url"
userId="user"
password="pwd" />
<javaTypeResolver>
<property name="forceBigDecimals" value="true" />
</javaTypeResolver>
<javaModelGenerator targetPackage="dal.entity.main" targetProject="src/main/java" />
<sqlMapGenerator targetPackage="dal.mapper.main"
targetProject="src/main/resources" />
<!-- 生成xml文件 -->
<javaClientGenerator targetPackage="dal.mapper.main"
targetProject="src/main/java" type="XMLMAPPER"/>
<table tableName="MAIN" />
</context>
</generatorConfiguration>
对应的 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+分页插件+分包