项目背景
项目采用springboot+mybatis-plus+druid。
其中druid数据源供mysql使用,信息配置在yml文件中:
spring:
main:
allow-bean-definition-overriding: true
profiles:
active: dev
application:
name: iotp
datasource:
url: jdbc:mysql://${mysql.ip}:3306/idap?characterEncoding=UTF-8&rewriteBatchedStatements=true&socketTimeout=0&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: ${mysql.username}
password: ${mysql.password}
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
# 使用druid数据源
druid:
max-active: 20
initial-size: 1
max-wait: 60000
min-idle: 1
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x' FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: false
max-open-prepared-statements: 20
# encrypt password
#filters: config,stat,wall,log4j
use-global-data-source-stat: true
connection-init-sqls:
- set names utf8mb4
问题场景
项目需要引入TDengine,于是在代码中也配置了供TDengine使用的数据源
@Configuration
public class TdengineDruidConfig {
@Value("${tdengine.db.driverClassName}")
private String driverClassName;
@Value("${tdengine.db.url}")
private String url;
@Value("${tdengine.db.username}")
private String username;
@Value("${tdengine.db.password}")
private String password;
@Value("${tdengine.db.maxActive}")
private String maxActive;
@Value("${tdengine.db.initialSize}")
private String initialSize;
@Value("${tdengine.db.maxWait}")
private String maxWait;
@Value("${tdengine.db.minIdle}")
private String minIdle;
@Value("${tdengine.db.timeBetweenEvictionRunsMillis}")
private String timeBetweenEvictionRunsMillis;
@Value("${tdengine.db.minEvictableIdleTimeMillis}")
private String minEvictableIdleTimeMillis;
@Value("${tdengine.db.maxEvictableIdleTimeMillis}")
private String maxEvictableIdleTimeMillis;
@Value("${tdengine.db.validationQuery}")
private String validationQuery;
@Value("${tdengine.db.testWhileIdle}")
private String testWhileIdle;
@Value("${tdengine.db.testOnBorrow}")
private String testOnBorrow;
@Value("${tdengine.db.testOnReturn}")
private String testOnReturn;
@Bean
public DataSource tdDatasource() {
Properties properties = new Properties();
properties.put("driverClassName",driverClassName);
properties.put("url",url);
properties.put("username",username);
properties.put("password",password);
properties.put("maxActive",maxActive); //maximum number of connection in the pool
properties.put("initialSize",initialSize);//initial number of connection
properties.put("maxWait",maxWait);//maximum wait milliseconds for get connection from pool
properties.put("minIdle",minIdle);//minimum number of connection in the pool
properties.put("timeBetweenEvictionRunsMillis",timeBetweenEvictionRunsMillis);// the interval milliseconds to test connection
properties.put("minEvictableIdleTimeMillis",minEvictableIdleTimeMillis);//the minimum milliseconds to keep idle
properties.put("maxEvictableIdleTimeMillis",maxEvictableIdleTimeMillis);//the maximum milliseconds to keep idle
properties.put("validationQuery",validationQuery); //validation query
properties.put("testWhileIdle",testWhileIdle); // test connection while idle
properties.put("testOnBorrow",testOnBorrow); // don't need while testWhileIdle is true
properties.put("testOnReturn",testOnReturn); // don't need while testWhileIdle is true
//create druid datasource
DataSource dataSource = null;
try {
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception exception) {
exception.printStackTrace();
}
return dataSource;
}
}
结果项目启动后,用postman调用后台接口时,原本正常的接口现在却抛出了异常,原因是数据源信息不对。
问题分析
MybatisPlusAutoConfiguration
类在构建SqlSessionFactory
时,需要DataSource
对象。
源代码如下
在没有引入TDengine数据源配置前,由于项目中不存在DataSource
类型的Bean,所以此处注入的DataSource
对象为我们在yml中配置的;
当引入TDengine数据源后,由于代码中已经存在DataSource
类型的Bean,所以此处注入的DataSource
对象为我们自己定义的,就没有用到yml中的配置。
问题解决
为了让MybatisPlusAutoConfiguration
类能获取到正确的DataSource
对象,需要将yml中的信息配置在代码中,并加上@Primary
注解标注,表示优先获取该DataSource
对象。
@Configuration
public class IotpDruidConfig {
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.druid.max-active}")
private String maxActive;
@Value("${spring.datasource.druid.initial-size}")
private String initialSize;
@Value("${spring.datasource.druid.max-wait}")
private String maxWait;
@Value("${spring.datasource.druid.min-idle}")
private String minIdle;
@Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
private String timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.min-evictable-idle-time-millis}")
private String minEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.validation-query}")
private String validationQuery;
@Value("${spring.datasource.druid.test-while-idle}")
private String testWhileIdle;
@Value("${spring.datasource.druid.test-on-borrow}")
private String testOnBorrow;
@Value("${spring.datasource.druid.test-on-return}")
private String testOnReturn;
@Value("${spring.datasource.druid.pool-prepared-statements}")
private String poolPreparedStatements;
@Value("${spring.datasource.druid.max-open-prepared-statements}")
private String maxOpenPreparedStatements;
@Value("${spring.datasource.druid.use-global-data-source-stat}")
private String useGlobalDataSourceStat;
@Bean
@Primary
public DataSource iotpDatasource() {
Properties properties = new Properties();
properties.put("driverClassName",driverClassName);
properties.put("url",url);
properties.put("username",username);
properties.put("password",password);
properties.put("maxActive",maxActive);
properties.put("initialSize",initialSize);
properties.put("maxWait",maxWait);
properties.put("minIdle",minIdle);
properties.put("timeBetweenEvictionRunsMillis",timeBetweenEvictionRunsMillis);
properties.put("minEvictableIdleTimeMillis",minEvictableIdleTimeMillis);
properties.put("validationQuery",validationQuery);
properties.put("testWhileIdle",testWhileIdle);
properties.put("testOnBorrow",testOnBorrow);
properties.put("testOnReturn",testOnReturn);
properties.put("poolPreparedStatements",poolPreparedStatements);
properties.put("maxOpenPreparedStatements",maxOpenPreparedStatements);
DataSource dataSource = null;
try {
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception exception) {
exception.printStackTrace();
}
return dataSource;
}
}