problem
A strange question on a recent project, the database is often every few hours, it reported the connection has been closed
Even the addition of the following configuration is also still does not work, the Internet did not find any articles that explain the pit
test-on-borrow: true
test-while-idle: true
validation-query: select 1 from dual
复制代码
Why can solve the above on configuring connection is interrupted can see three articles
Investigation
Online finding out, it can only own scrutiny guess. Because it is configured mybatis multiple data sources, each db config I have specifically written as a connection configuration.
Watching DataSourceConfig code, I suddenly thought, because I will not use the default method of creating a DataSource, so I did not read to write application.yml configuration:
@Bean(name = "db1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.db1")
@Primary
public DataSource dbDataSource() {
return DataSourceBuilder.create().build();
}
复制代码
Decisive follow-up build () method
public DataSource build() {
Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiate(type);
maybeGetDriverClassName();
bind(result);
return result;
}
复制代码
Make a break point at this time can see the result returned is a new DataSource
So we can dbDataSource modify () method, we write the configuration parameters:
@Value("${spring.datasource.db1.url}")
private String url;
@Value("${spring.datasource.db1.username}")
private String username;
@Value("${spring.datasource.db1.password}")
private String password;
@Value("${spring.datasource.db1.tomcat.test-on-borrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.db1.tomcat.test-while-idle}")
private boolean testWhileIdle;
@Value("${spring.datasource.db1.tomcat.validation-query}")
private String validationQuery;
@Value("${spring.datasource.db1.tomcat.max-idle}")
private int maxIdle;
@Value("${spring.datasource.db1.tomcat.min-idle}")
private int minIdle;
@Value("${spring.datasource.db1.tomcat.initial-size}")
private int initialSize;
@Value("${spring.datasource.db1.tomcat.max-active}")
private int maxActive;
@Value("${spring.datasource.db1.tomcat.time-between-eviction-runs-millis}")
private int timeBetweenEvictionRunsMillis;
@Bean(name = "db1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.db1")
@Primary
public DataSource dbDataSource() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaxActive(maxActive);
dataSource.setMinIdle(minIdle);
dataSource.setMaxIdle(maxIdle);
dataSource.setTestOnBorrow(testOnBorrow);
dataSource.setTestWhileIdle(testWhileIdle);
dataSource.setValidationQuery(validationQuery);
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
dataSource.setInitialSize(initialSize);
return dataSource;
//return DataSourceBuilder.create().build();
}
复制代码
Secondary investigation
You can really solve the problem by the above method, but I suddenly thought, DataSource created by default is not necessary basic information url, username, password, etc. That's why these configuration parameters and can be written into it?
This time I see we have a dbDataSource method @Bean(name = "db1DataSource")
, so bold guess we inject these configuration parameters is the first time created by Spring's IOC injection. Debug by I found the fact that it is.
Method DataBinder break point bind class,
public void bind(PropertyValues pvs) {
MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues) ?
(MutablePropertyValues) pvs : new MutablePropertyValues(pvs);
doBind(mpvs);
}
复制代码
We can see the call path method
See the familiar refresh Dafa, this part of the source code associated Look Spring Spring source code analysis
At this time only last a doubt, our url, username, password, etc. since DataSource injected into the inside through the IOC, other arguments why not? With my DataSource class all the way up to find his father class interface PoolConfiguration, see all parameters and getset method.
Look at my application.yml configuration file parameters
spring:
datasource:
db1:
url:
username:
password:
driver-class-name: oracle.jdbc.driver.OracleDriver
tomcat:
max-wait: 10000
max-active: 30
test-on-borrow: true
max-idle: 5
db2:
xxx
....
复制代码
Finally found this one up!
Spring data original default tomcat-jdbc connection pool when the parameter settings are
spring:
datasource:
url:
username:
password:
driver-class-name: oracle.jdbc.driver.OracleDriver
tomcat:
max-wait: 10000
max-active: 30
test-on-borrow: true
max-idle: 5
复制代码
And when using a multi data source configuration and simple that you can just copy the past, so when the IOC Spring injection, read to tomcat.max-wait does not match the DataSource in the setMaxWait method. Nature will not work.
So this problem only need to configure the file to read as follows
spring:
datasource:
db1:
url:
username:
password:
driver-class-name: oracle.jdbc.driver.OracleDriver
max-wait: 10000
max-active: 30
test-on-borrow: true
test-while-idle: true
validation-query: select 1 from dual
max-idle: 5
db2:
xxx
....
复制代码
to sum up
The problem from the results, then it is not simple, but from the process, not only let me go over it again and spring IOC process, let me feel this issue step by step dissection, more knowledge to connect the dots the sense of accomplishment. If you do not learn until spring source, the high probability I would not think it to see the bean injection