Ошибка закрытия соединения после некоторого простоя - PullRequest
0 голосов
/ 25 мая 2018

У меня есть мультитенантное приложение, в котором настроена одна БД на каждого арендатора с одной главной БД.Я загружаю все источники данных в приложениях примерно так:

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

В контроллере я устанавливаю соответствующий источник данных как (аналогично источникам данных TENANT):

TenantContext.setCurrentTenant("MASTER");

Проблема: При запуске сервера все работает нормально (как запросы MASTER DB, так и запросы TENANT), но по прошествии некоторого времени (несколько часов) сервер бездействует, а определенные вызовы арендатора начинают давать сбои (в то время как соединения с MASTER DB по-прежнему работают нормально) с ошибкой:

Не удалось открыть JPA EntityManager для транзакции;вложенное исключение: javax.persistence.PersistenceException: com.microsoft.sqlserver.jdbc.SQLServerException: соединение закрыто.

Пожалуйста, помогите мне избавиться от этого исключения.Заранее спасибо.

1 Ответ

0 голосов
/ 01 июня 2018

У меня также есть проблема и решения:

Почему закрываются соединения арендатора? Поскольку автоматические конфигурации (@ConfigurationProperties (prefix = "spring.datasource")) из spring-boot не применяется к источникам данных клиента, которые я создавал в коде.

Resolution- Я добавил новый метод для установки свойств пула соединений 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;
}

Это решило мою проблему.Но мне любопытно узнать, есть ли способ применить автоконфигурации при создании объектов в весенней загрузке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...