0 导言
本文主要介绍使用Springboot框架配置多个数据源。
使用的主要框架以及数据库版本(已测试通过):
Springboot 3.2.1
Mybatis-plus 3.5.4.1
MySQL 8.0.30
1 实现(以两个数据源为例)
1.1 依赖配置
和单一数据源配置无区别
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4.1</version>
<exclusions>
<exclusion>
<artifactId>mybatis-spring</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.4.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>3.5.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
1.2 yml配置
数据库相关配置:
spring:
datasource:
db-article:
jdbc-url: jdbc:mysql://localhost:3306/leadnews_article?useSSL=false&useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
db-user:
jdbc-url: jdbc:mysql://localhost:3306/leadnews_user?useSSL=false&useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
放一张图来比较配置一个数据源和配置多个数据源的不同
- 为每个数据库起个名字。注意如果想使用连接符,不要使用下划线 ‘_’,虽然写的时候没错误,但是编译时会报错。
url
改成jdbc-url
1.3 配置数据源
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
/**
* 数据源配置
*/
@Configuration
public class DataSourceConfig {
@Primary
@Bean(name = "db_article")
@ConfigurationProperties(prefix = "spring.datasource.db-article")
public DataSource dBSrcArticle() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "db_user")
@ConfigurationProperties(prefix = "spring.datasource.db-user")
public DataSource dBSrcUser() {
return DataSourceBuilder.create().build();
}
}
注意要加上Primary注解。
配置SqlSessionFactory
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
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.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
/**
* 数据库leadnews_article
*/
@Configuration
@MapperScan(basePackages = {"com.mapper.article"}, sqlSessionFactoryRef = "sqlSessionFactoryArticle")
public class DBSrcArticle {
@Bean
public SqlSessionFactory sqlSessionFactoryArticle(@Qualifier("db_article") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:**/*.xml"));
return sqlSessionFactory.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplateArticle(@Qualifier("sqlSessionFactoryArticle") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
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;
/**
* 数据库leadnews_user
*/
@Configuration
@MapperScan(basePackages = {"com.mapper.user"}, sqlSessionFactoryRef = "sqlSessionFactoryUser")
public class dBSrcUser {
@Bean
@Primary
public SqlSessionFactory sqlSessionFactoryUser(@Qualifier("db_user") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:**/*.xml"));
return sqlSessionFactory.getObject();
}
@Bean
@Primary
public SqlSessionTemplate sqlSessionTemplateUser(@Qualifier("sqlSessionFactoryUser") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
说明:
-
两个数据源需要配置两个sqlSessionFactory
-
这里不同的数据源的sqlSessionFactory的名字不可以相同,且在使用时必须通过名字指名使用的是哪一个数据源。且需要标注一个为主数据源,即加上
@Primary
注解 -
单一数据源时所有的mapper文件都直接放置在mapper目录下,多个数据源则要对这些mapper文件进行分离,以此来区分使用的数据库,如此时的mapper文件层级如下图,所以此时注解
@MapperScan
的basepackages
与sqlSessionFactoryRef
指定的SqlSessionFactory是一一对应的。
1.4 修改启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan(basePackages = {"com.rain.mapper.article"}, sqlSessionFactoryRef = "sqlSessionFactoryArticle")
@MapperScan(basePackages = {"com.rain.mapper.user"}, sqlSessionFactoryRef = "sqlSessionFactoryUser")
在启动类上加上以上三个注解即可。
exclude = {DataSourceAutoConfiguration.class}
,排除这个的主要原因是我们使用了自定义的数据源,而不是使用Springboot服务启动时对于数据源配置的自动导入。- 这里再次使用了
MapperScan
注解,与配置SqlSessionFactory
时使用的没有什么区别。在我自己测试的过程中,只在启动类加上MapperScan
注解即可。如果启动类上不加,则会出现两种错误:
a. 如果没有此注解,则运行失败:
b. 如果不指名对应关系或对应关系错误,则会出现数据库与数据库中表不匹配的情况,即系统认为只有一个数据源,报错信息如下:
article表自然在user库中不存在。
2 其它问题
2.1 Mybatis & Mybatis-plus
在配置SqlSessionFactory时需要注意,如果使用的是Mybatis-plus,则按照1中实现即可,如果使用的是Mybatis,则
//MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
//Mybatis使用下面这个
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
如果不正确使用,会出现无法正常使用BaseMapper的问题
报错如BindingException:Invalid bound statement (not found) XXX selectList
2.2 @Primary
@Primary注解可以标注出有多个候选者有资格自动装配单值依赖项时,优先考虑的Bean对象,如果没有或者标了多个都会出现错误
3 总结
本文讲述了如何实现多数据源配置。
除了这种方式,还有很多其它方式,比如Mybatis-plus中提供的动态数据源SpringBoot的starter:dynamic-datasource-spring-boot-starter
来实现,再比如使用ThreadLocal+AbstractRoutingDataSource
的方式实现,有兴趣之后自行探索。
ps:运行项目中发现mybatis-plus的图案还是很可爱的