例子及场景:最近使用SpringBoot+durid需要连接多个数据源:同时支持MySQL、Oracle,遇到问题及处理方法总结如下:
pom.xml配置:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.6.RELEASE
com.ywx
springboot-bi
0.0.1-SNAPSHOT
springboot-bi
Demo project for Spring Boot
1.8
1.3.2
1.1.13
3.17
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-starter-test
test
org.apache.commons
commons-lang3
com.github.pagehelper
pagehelper-spring-boot-starter
1.2.10
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis.boot.version}
com.alibaba
druid-spring-boot-starter
${druid.version}
com.oracle
ojdbc14
10.2.0.1.0
mysql
mysql-connector-java
5.1.6
org.springframework.boot
spring-boot-starter-thymeleaf
org.yaml
snakeyaml
org.apache.poi
poi-ooxml
${poi.version}
org.springframework.boot
spring-boot-maven-plugin
注:oracle驱动包在maven仓库中找不到,需下载手动导入到maven仓库。
yml配置文件:
spring:
datasource:
druid:
datasource1:
url: jdbc:oracle:thin:@10.xx.xx.xx:1521:orcl
username: xxxx
password: xxxx
driverClassName: oracle.jdbc.OracleDriver
datasource2:
# 数据源开关/默认关闭
url: jdbc:oracle:thin:@10.xx.xx.xx:1521:orcl
username: xepacs
password: xxx
driverClassName: oracle.jdbc.driver.OracleDriver
datasource3:
url: jdbc:mysql://10.xx.xx.xx:3306/ecg
username: ecg
password: xxx
driverClassName: com.mysql.jdbc.Driver
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
statViewServlet:
enabled: true
url-pattern: /monitor/druid/*
filter:
stat:
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
数据源基本参数配置类:
package com.ywx.framework.config.properties;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 数据源配置文件封装类.
*
* @author ybc
* @date 2019-06-25-10:17
*/
@Configuration
public class DruidProperties {
@Value("${spring.datasource.druid.initialSize}")
private int initialSize;
@Value("${spring.datasource.druid.minIdle}")
private int minIdle;
@Value("${spring.datasource.druid.maxActive}")
private int maxActive;
@Value("${spring.datasource.druid.maxWait}")
private int maxWait;
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
private int maxEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.druid.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.druid.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.druid.testOnReturn}")
private boolean testOnReturn;
public DruidDataSource dataSource(DruidDataSource datasource) {
/** 配置初始化大小、最小、最大 */
datasource.setInitialSize(initialSize);
datasource.setMaxActive(maxActive);
datasource.setMinIdle(minIdle);
/** 配置获取连接等待超时的时间 */
datasource.setMaxWait(maxWait);
/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
/** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
/**
* 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
*/
datasource.setValidationQuery(validationQuery);
/** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
datasource.setTestWhileIdle(testWhileIdle);
/** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
datasource.setTestOnBorrow(testOnBorrow);
/** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
datasource.setTestOnReturn(testOnReturn);
return datasource;
}
}
数据源配置类:
package com.ywx.framework.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.ywx.framework.common.enums.DataSourceType;
import com.ywx.framework.config.properties.DruidProperties;
import com.ywx.framework.datasource.DynamicDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author ywx
* @date 2019-06-25-10:16
*/
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid.datasource1")
public DataSource tmsDataSource(DruidProperties druidProperties) {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean
@ConfigurationProperties("spring.datasource.druid.datasource2")
//@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource pacsDataSource(DruidProperties druidProperties) {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean
@ConfigurationProperties("spring.datasource.druid.datasource3")
public DataSource ecgDataSource(DruidProperties druidProperties) {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource tmsDataSource, DataSource pacsDataSource, DataSource ecgDataSource) {
Map
以上,已经完成了MySQL和Oracle数据源的配置了,数据源可以正常连接,但是查询数据后如果需要通过PageHelper实现分页的话,还需要配置PageHelper支持不同类型数据库分页sql的切换。
如果使用单库连接,可以使用以下配置:
# PageHelper分页插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
可以参考PageHelper官网文档
(1) helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
(2) offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
(3) rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
(4) pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
(5) reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
(6) params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
(7) supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest。
(8) autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver)
如果使用多数据源,需要修改pagehelper配置项,配置如下:
# PageHelper分页插件
pagehelper:
# helperDialect: mysql
reasonable: false
supportMethodsArguments: true
params: count=countSql
# 默认false,当为true时,自动检验适合的数据库
auto-dialect: true
# 这个一定要加上,不然mysql和oracle分页两个只能用一个,另一个会报错,加上后,两中数据库分页都可以用了
auto-runtime-dialect: true
以上,已经完成支持不同类型数据库多数据源的连接已经分页实现了。