Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 空闲一段时间后连接关闭错误_Sql Server_Azure_Spring Boot_Sql Server 2012_Multi Tenant - Fatal编程技术网

Sql server 空闲一段时间后连接关闭错误

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

我有一个多租户应用程序,其中每个租户配置一个DB和一个主DB。我在应用程序中加载所有数据源,如下所示:

@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;
}