距上篇文章《Spring Boot 初级入门教程(十八) —— 集成 MyBatis 另外一种开发方式》已跨了两个年头,时间确实有些久了!!!这么久没更新这个系列,一则由于自己确实忙了些,项目一个接一个的加班整;再者,由于项目需要,写了些其它方面的文章,比如关于 kafka、redis、IDEA 等。
另外,自己又买了个共享虚机,开通了尘封已久的博客,由于 .com 域名被别人抢注了,所以换成了 menglanglang.cn,如果有兴趣,也可以踩踩。
在开始这篇之前,首先要做的一件事,就是把原来的 demo 源码包中,包名换一下。因为原来一直是 com.menglanglang.xxx,现在换成 cn.menglanglang.xxx。如下:


另外,把代码中的原博客地址 http://blog.csdn.net/tzhuwb 换成 http://www.menglanglang.cn,纯属个人强迫症,理解。
言归正传,在项目开发中,我们常常会碰到一个服务配置多个数据源的情况,有些项目同时配置四五个 oracle,还配置着 mysql,gbase 等等。所以这篇主要说说如何简单的配置多数据源。
这里就简单以前面配置过的 oracle 和 mysql,同时配置到项目中,业务上同时操作不同的库来举例说明配置多数据源的步骤。
第一步,添加依赖包
在 pom 文件中,添加支持数据库连接池的 druid 依赖包,代码如下:
<!-- 添加数据库连接池插件,支持多数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
添加 Oracle 和 MySQL 依赖包,代码如下:
<!-- mysql jdbc 插件 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- oracle jdbc 插件 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.1.0</version>
</dependency>
第二步,修改配置文件
在 application.properties 中,同时添加 oracle 数据库配置和 MySQL 数据库配置,分别用 first 和 second 来标识第一个和第二个数据源,代码如下所示:
- #################################
- ## Oracle 数据库配置
- #################################
- # Oracle数据库连接
- spring.datasource.first.url=jdbc:oracle:thin:@192.168.220.240:1521:orcl
- # Oracle数据库用户名
- spring.datasource.first.username=scott
- # Oracle数据库密码
- spring.datasource.first.password=123456
- # Oracle数据库驱动(该配置可以不用配置,因为Spring Boot可以从url中为大多数数据库推断出它)
- spring.datasource.first.driver-class-name=oracle.jdbc.OracleDriver
- #################################
- ## MySQL 数据库配置
- #################################
- # MySQL数据库连接
- spring.datasource.second.url=jdbc:mysql://192.168.220.240:3306/test_springboot?characterEncoding=UTF-8
- # MySQL数据库用户名
- spring.datasource.second.username=root
- # MySQL数据库密码
- spring.datasource.second.password=123456
- # MySQL数据库驱动(该配置可以不用配置,因为Spring Boot可以从url中为大多数数据库推断出它)
- spring.datasource.second.driver-class-name=com.mysql.jdbc.Driver
- #################################
- ## 数据库共通配置
- #################################
- spring.datasource.max-active=10
- spring.datasource.max-wait=10000
- spring.datasource.min-idle=5
- spring.datasource.initial-size=5
- #spring.datasource.validation-query=SELECT 1 FROM DUAL
- #spring.datasource.test-on-borrow=true
- #spring.datasource.test-while-idle=true
- #spring.datasource.time-between-eviction-runs-millis=18800
- #spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=10000)
第三步,添加配置类,分别读取数据库配置
创建一个包 config,分别创建 FirstDataSourceConfig 和 SecondDataSourceConfig,结构和代码如下:

FirstDataSourceConfig.java:
- package cn.menglanglang.test.springboot.config;
- import java.util.Objects;
- import javax.sql.DataSource;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.SqlSessionTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- 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.env.Environment;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.jdbc.datasource.DataSourceTransactionManager;
- import com.alibaba.druid.pool.DruidDataSource;
- @Configuration
- public class FirstDataSourceConfig {
- @Autowired
- private Environment environment;
- @Bean(name = "firstDataSource")
- @Primary
- public DataSource firstDataSource() {
- DruidDataSource dataSource = new DruidDataSource();
- String prefix = "spring.datasource";
- String prefixFirst = "spring.datasource.first";
- dataSource.setName("firstDataSource");
- dataSource.setDriverClassName(environment.getProperty(prefixFirst + ".driver-class-name").trim());
- dataSource.setUrl(environment.getProperty(prefixFirst + ".url").trim());
- dataSource.setUsername(environment.getProperty(prefixFirst + ".username").trim());
- dataSource.setPassword(environment.getProperty(prefixFirst + ".password").trim());
- dataSource.setMaxActive(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".max-active")).trim()));
- dataSource.setMinIdle(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".min-idle")).trim()));
- dataSource.setInitialSize(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".initial-size")).trim()));
- dataSource.setMaxWait(Long.parseUnsignedLong(Objects.requireNonNull(environment.getProperty(prefix + ".max-wait")).trim()));
- // dataSource.setTimeBetweenEvictionRunsMillis(Long.parseUnsignedLong(Objects.requireNonNull(environment.getProperty(prefix + ".time-between-eviction-runs-millis")).trim()));
- // dataSource.setMinEvictableIdleTimeMillis(Long.parseUnsignedLong(Objects.requireNonNull(environment.getProperty(prefix + ".min-evictable-idle-time-millis")).trim()));
- // dataSource.setTestWhileIdle(Boolean.parseBoolean(environment.getProperty(prefix + ".test-while-idle")));
- // dataSource.setTestOnBorrow(Boolean.parseBoolean(environment.getProperty(prefix + ".test-on-borrow")));
- // dataSource.setTestOnBorrow(Boolean.parseBoolean(environment.getProperty(prefix + ".test-on-return")));
- // dataSource.setTestOnBorrow(Boolean.parseBoolean(environment.getProperty(prefix + ".async-close-connection-enable")));
- // dataSource.setValidationQueryTimeout(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".validation-query-timeout")).trim()));
- // dataSource.setValidationQuery(environment.getProperty(prefix + ".validation-query"));
- return dataSource;
- }
- @Bean(name = "firstTransactionManager")
- @Primary
- public DataSourceTransactionManager firstTransactionManager() {
- return new DataSourceTransactionManager(firstDataSource());
- }
- @Bean(name = "firstSqlSessionFactory")
- @Primary
- public SqlSessionFactory firstSqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource) throws Exception {
- final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean() {
- {
- setDataSource(dataSource);
- setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/oracle/**/*.xml"));
- }
- };
- return sessionFactory.getObject();
- }
- @Bean(name = "firstSqlSessionTemplate")
- @Primary
- public SqlSessionTemplate firstSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
- return new SqlSessionTemplate(sqlSessionFactory);
- }
- }
SecondDataSourceConfig.java:
- package cn.menglanglang.test.springboot.config;
- import java.util.Objects;
- import javax.sql.DataSource;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.mybatis.spring.SqlSessionTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.env.Environment;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.jdbc.datasource.DataSourceTransactionManager;
- import com.alibaba.druid.pool.DruidDataSource;
- @Configuration
- public class SecondDataSourceConfig {
- @Autowired
- private Environment environment;
- @Bean(name = "secondDataSource")
- public DataSource secondDataSource() {
- DruidDataSource dataSource = new DruidDataSource();
- String prefix = "spring.datasource";
- String prefixSecond = "spring.datasource.second";
- dataSource.setName("secondDataSource");
- dataSource.setDriverClassName(environment.getProperty(prefixSecond + ".driver-class-name").trim());
- dataSource.setUrl(environment.getProperty(prefixSecond + ".url").trim());
- dataSource.setUsername(environment.getProperty(prefixSecond + ".username").trim());
- dataSource.setPassword(environment.getProperty(prefixSecond + ".password").trim());
- dataSource.setMaxActive(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".max-active")).trim()));
- dataSource.setMinIdle(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".min-idle")).trim()));
- dataSource.setInitialSize(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".initial-size")).trim()));
- dataSource.setMaxWait(Long.parseUnsignedLong(Objects.requireNonNull(environment.getProperty(prefix + ".max-wait")).trim()));
- // dataSource.setTimeBetweenEvictionRunsMillis(Long.parseUnsignedLong(Objects.requireNonNull(environment.getProperty(prefix + ".time-between-eviction-runs-millis")).trim()));
- // dataSource.setMinEvictableIdleTimeMillis(Long.parseUnsignedLong(Objects.requireNonNull(environment.getProperty(prefix + ".min-evictable-idle-time-millis")).trim()));
- // dataSource.setTestWhileIdle(Boolean.parseBoolean(environment.getProperty(prefix + ".test-while-idle")));
- // dataSource.setTestOnBorrow(Boolean.parseBoolean(environment.getProperty(prefix + ".test-on-borrow")));
- // dataSource.setTestOnBorrow(Boolean.parseBoolean(environment.getProperty(prefix + ".test-on-return")));
- // dataSource.setTestOnBorrow(Boolean.parseBoolean(environment.getProperty(prefix + ".async-close-connection-enable")));
- // dataSource.setValidationQueryTimeout(Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + ".validation-query-timeout")).trim()));
- // dataSource.setValidationQuery(environment.getProperty(prefix + ".validation-query"));
- return dataSource;
- }
- @Bean(name = "secondTransactionManager")
- public DataSourceTransactionManager secondTransactionManager() {
- return new DataSourceTransactionManager(secondDataSource());
- }
- @Bean(name = "secondSqlSessionFactory")
- public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception {
- final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean() {
- {
- setDataSource(dataSource);
- setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/mysql/**/*.xml"));
- }
- };
- return sessionFactory.getObject();
- }
- @Bean(name = "secondSqlSessionTemplate")
- public SqlSessionTemplate secondSqlSessionTemplate(@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
- return new SqlSessionTemplate(sqlSessionFactory);
- }
- }
第四步,扩展数据库接口查询封装类
接口查询封装类 DaoHelper.java,放在 common 包下,接口如下:

FirstDaoHelper.java:
- package cn.menglanglang.test.springboot.common;
- import java.util.List;
- import java.util.Map;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.stereotype.Component;
- /**
- * @desc 数据库查询封装
- *
- * @see 封装了基本的查询方法,包括增删改查分页查等。 使用此类时,使用 @Resource 或 @Autowired 注解注入。
- * @author 孟郎郎
- * @blog http://www.menglanglang.cn
- * @version 1.0
- * @date 2020年3月19日下午11:02:03
- */
- @Component
- public class FirstDaoHelper {
- @Autowired
- @Qualifier("firstSqlSessionTemplate")
- private SqlSessionTemplate sqlSessionTemplate;
- public FirstDaoHelper(SqlSessionTemplate sqlSessionTemplate) {
- this.sqlSessionTemplate = sqlSessionTemplate;
- }
- /**
- * 获取sqlsession factory
- */
- public SqlSessionFactory getSqlSessionFactory() {
- return this.sqlSessionTemplate.getSqlSessionFactory();
- }
- // 这部分和前篇文章中的DaoHelper完全一样,在此省略。。。
- }
SecondDaoHelper.java:
- package cn.menglanglang.test.springboot.common;
- import java.util.List;
- import java.util.Map;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.stereotype.Component;
- /**
- * @desc 数据库查询封装
- *
- * @see 封装了基本的查询方法,包括增删改查分页查等。 使用此类时,使用 @Resource 或 @Autowired 注解注入。
- * @author 孟郎郎
- * @blog http://www.menglanglang.cn
- * @version 1.0
- * @date 2020年3月19日下午11:01:34
- */
- @Component
- public class SecondDaoHelper {
- @Autowired
- @Qualifier("secondSqlSessionTemplate")
- private SqlSessionTemplate sqlSessionTemplate;
- public SecondDaoHelper(SqlSessionTemplate sqlSessionTemplate) {
- this.sqlSessionTemplate = sqlSessionTemplate;
- }
- /**
- * 获取sqlsession factory
- */
- public SqlSessionFactory getSqlSessionFactory() {
- return this.sqlSessionTemplate.getSqlSessionFactory();
- }
- // 这部分和前篇文章中的DaoHelper完全一样,在此省略。。。
- }
第五步,修改测试类、接口类、实现类及 xml 文件
这步骤相当于把《Spring Boot 初级入门教程(十五) —— 集成 MyBatis》和《Spring Boot 初级入门教程(十八) —— 集成 MyBatis 另外一种开发方式》中的代码合并一起,这里就不再详细贴了,可以直接下载打包好的源码查看即可。
分别为:MyBatisController3.java、MyBatisService3.java、MyBatisServiceImpl3.java、mybati-mapper3.xml。
第六步,测试
启动项目,分别访问以下路径,可以看到原来 Oracle 和 MySQL 的接口都可以拿到数据。




可以看到与原来的测试结果完全一致,所以可以同时使用两个数据源配置。
到此,多数据源简单配置步骤结束。^ ^
但一般项目中用到最多,也是最难的部分,是各个数据源参数的配置,以达到访问效率最优,需要结合服务部署机器资源配置,数据库配置,并发访问量等各个指标,来调节数据源参数。这里把常常用到的参数顺便罗列一下,便于服务调优查询。
yml 配置文件格式:
- druid:
- access-to-underlying-connection-allowed: false #允许访问底层连接
- active-connection-stack-trace: #活跃连接堆跟踪
- active-connections: #活跃连接列表
- aop-patterns: #AOP模式
- async-close-connection-enable: false #启用异步关闭连接
- async-init: false #异步初始化
- break-after-acquire-failure: false #失败后跳过
- clear-filters-enable: false #启动清除过滤器
- connect-properties: #连接配置
- connection-error-retry-attempts: 1 #连接出错尝试几次重新连接
- connection-init-sqls: #连接初始化语句
- connection-properties: #连接属性
- create-scheduler: #创建程序
- db-type: #DB类型
- default-auto-commit: false #默认自动提交
- default-catalog: #默认目录
- default-read-only: false #默认只读
- default-transaction-isolation: 1 #默认事务隔离
- destroy-scheduler: #销毁程序
- driver: #驱动类
- driver-class-name: #驱动类名
- dup-close-log-enable: true #启用DUP关闭日志
- enable: true #启动连接池
- exception-sorter:
- exception-sorter-class-name:
- fail-fast: true #快速失败?
- filter-class-names: #过滤器类名称
properties 配置文件格式:
- #连接池属性
- spring.datasource.druid.initial-size=15
- spring.datasource.druid.max-active=100
- spring.datasource.druid.min-idle=15
- spring.datasource.druid.max-wait=60000
- spring.datasource.druid.time-between-eviction-runs-millis=60000
- spring.datasource.druid.min-evictable-idle-time-millis=300000
- spring.datasource.druid.test-on-borrow=false
- spring.datasource.druid.test-on-return=false
- spring.datasource.druid.test-while-idle=true
- spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
- spring.datasource.druid.validation-query-timeout=1000
- spring.datasource.druid.keep-alive=true
- spring.datasource.druid.remove-abandoned=true
- spring.datasource.druid.remove-abandoned-timeout=180
- spring.datasource.druid.log-abandoned=true
- spring.datasource.druid.pool-prepared-statements=true
- spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
- spring.datasource.druid.filters=stat,wall,slf4j
- spring.datasource.druid.use-global-data-source-stat=true
- spring.datasource.druid.preparedStatement=true
- spring.datasource.druid.maxOpenPreparedStatements=100
- spring.datasource.druid.connect-properties.mergeSql=true
- spring.datasource.druid.connect-properties.slowSqlMillis=5000
属性说明:


源码下载:https://pan.baidu.com/s/1jA_EDzoUeXhgNA-e7wsnYA (提取码:4i84)
原文链接: https://blog.csdn.net/tzhuwb/article/details/104956070