Sql server 空闲一段时间后连接关闭错误
我有一个多租户应用程序,其中每个租户配置一个DB和一个主DB。我在应用程序中加载所有数据源,如下所示:Sql server 空闲一段时间后连接关闭错误,sql-server,azure,spring-boot,sql-server-2012,multi-tenant,Sql Server,Azure,Spring Boot,Sql Server 2012,Multi Tenant,我有一个多租户应用程序,其中每个租户配置一个DB和一个主DB。我在应用程序中加载所有数据源,如下所示: @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource() { if(LOGGER.isInfoEnabled()) LOGGER.info("Loading datasources ..."); DataSource ds = nul
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource dataSource() {
if(LOGGER.isInfoEnabled())
LOGGER.info("Loading datasources ...");
DataSource ds = null;
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
// load MASTER datasource
ds = dataSourceLookup.getDataSource(properties.getJndiName());
// load other TENANTs DB details
JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);
List<GroupConfig> groupConfigs = jdbcTemplate.query(
"select * from master.tblTenant where IsActive=1 and ConfigCode in ('DB_URL','DATASOURCE_CLASS','USER_NAME','DB_PASSWORD') order by 2",
new ResultSetExtractor<List<GroupConfig>>() {
public List<GroupConfig> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<GroupConfig> list = new ArrayList<GroupConfig>();
while (rs.next()) {
GroupConfig groupConfig = new GroupConfig();
groupConfig.setGroupConfigId(rs.getLong(1));
groupConfig.setGroupCode(rs.getString(2));
groupConfig.setConfigCode(rs.getString(3));
groupConfig.setConfigValue(rs.getString(4));
groupConfig.setIsActive(rs.getBoolean(5));
list.add(groupConfig);
}
return list;
}
});
int propCount = 1;
Map<String, Map<String, String>> groups = new HashMap<String, Map<String, String>>();
Map<String, String> temp = new HashMap<String, String>();
for (GroupConfig config : groupConfigs) {
temp.put(config.getConfigCode(), config.getConfigValue());
if (propCount % 4 == 0) {
groups.put(config.getGroupCode(), temp);
temp = new HashMap<String, String>();
}
propCount++;
}
// Create TENANT dataSource
Map<Object, Object> resolvedDataSources = new HashMap<Object, Object>();
for (String tenantId : groups.keySet()) {
Map<String, String> groupKV = groups.get(tenantId);
DataSourceBuilder dataSourceBuilder = new DataSourceBuilder(this.getClass().getClassLoader());
dataSourceBuilder.driverClassName(groupKV.get("DATASOURCE_CLASS")).url(groupKV.get("DB_URL"))
.username(groupKV.get("USER_NAME")).password(groupKV.get("DB_PASSWORD"));
//System.out.println(dataSourceBuilder.findType()); //class org.apache.tomcat.jdbc.pool.DataSource
if (properties.getType() != null) {
dataSourceBuilder.type(properties.getType());
}
if(LOGGER.isInfoEnabled())
LOGGER.info("Building datasource : "+tenantId);
resolvedDataSources.put(tenantId, dataSourceBuilder.build());
}
resolvedDataSources.put("MASTER", ds);
MultitenantDataSource dataSource = new MultitenantDataSource();
dataSource.setTargetDataSources(resolvedDataSources);
dataSource.setDataSourceLookup(dataSourceLookup);
dataSource.afterPropertiesSet();
if(LOGGER.isInfoEnabled())
LOGGER.info("Datasources initialization finished !");
return dataSource;
}
问题:在服务器启动时,一切正常(主数据库和特定于租户的查询),但一旦服务器空闲一段时间(数小时),特定于租户的调用开始失败(而主数据库连接仍然正常),并出现错误:
无法为事务打开JPA EntityManager;嵌套异常为javax.persistence.PersistenceException:com.microsoft.sqlserver.jdbc.SQLServerException:连接已关闭
请帮我摆脱这个例外。提前感谢。我也得到了问题和解决方案: 为什么租户连接被关闭?因为spring boot的自动配置(@ConfigurationProperties(prefix=“spring.datasource”))没有应用到我在代码中创建的租户数据源上 解析-我添加了新方法来设置tomcat连接池属性:
private DataSource buildDataSource(String driverClass, String url, String user, String pass){
PoolProperties p = new PoolProperties();
p.setUrl(url);
p.setDriverClassName(driverClass);
p.setUsername(user);
p.setPassword(pass);
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(30000);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMaxActive(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
DataSource datasource = new DataSource();
datasource.setPoolProperties(p);
return datasource;
}
这解决了我的问题。但我很想知道,在spring boot中创建对象时,是否有方法应用自动配置。稍微绕道一点。对于手头的问题,您似乎需要先检查连接并打开它。
private DataSource buildDataSource(String driverClass, String url, String user, String pass){
PoolProperties p = new PoolProperties();
p.setUrl(url);
p.setDriverClassName(driverClass);
p.setUsername(user);
p.setPassword(pass);
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(30000);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMaxActive(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
DataSource datasource = new DataSource();
datasource.setPoolProperties(p);
return datasource;
}