У меня есть приложение службы отдыха, работающее на платформе Java Spring. Приложение зависит от подключения к внешней базе данных MySQL, которая подключается через JDBC.
Моя проблема заключается в поддержании прочной связи между остальной службой и базой данных MySQL. У меня есть то, что я считаю рудиментарным отказоустойчивым соединением, которое выглядит примерно так:
public Connection getConnection() throws SQLException {
if(connection == null){
this.buildConnection();
}
else if(!connection.isValid(10)){ //Rebuild connection if it is no longer valid
connection.close();
this.buildConnection();
}
return connection;
}
Использование этого метода должно гарантировать, что соединение действительно до выполнения любого запроса. Моя проблема в том, что я периодически получаю исключение при вызове этого метода:
Не удалось создать соединение с сервером базы данных. Пытался переподключиться 3 раза. Сдаваться. SQLState: 08001. Код ошибки: 0.
Вещи, которые меня очень озадачили по этому поводу:
- Эта ошибка возникает только периодически. Много раз соединение работает, просто найдите.
- Я тестирую это же приложение на своей машине разработчика, и эта ошибка никогда не возникает.
Я специально настроил базу данных MySQL на своем собственном сервере, поэтому я контролирую все ее параметры конфигурации. Из этого я знаю, что эта проблема не связана с максимальным количеством разрешенных подключений или тайм-аутом подключения.
Изменить — Обновление 1:
- Эта служба размещается как облачная служба на платформе Microsoft Azure.
- Я случайно поставил его как экземпляр в Северной Европе, а БД находится в Северной Америке - возможно, не связано, но пытаюсь нарисовать всю картину.
- Пробовал совет по этой ссылке безуспешно. Не использовать пулы потоков, и все ResultSets и Statements/PreparedStatements после этого закрываются.
Изменить — Обновление 2
После некоторого рефакторинга мне удалось успешно реализовать пул соединений HikariCP, как описано @M.Deinum ниже. К сожалению, такая же проблема сохраняется. На моем локальном компьютере все отлично работает, и все модульные тесты проходят, но как только я отправляю его в Azure и жду между запросами более нескольких минут, я получаю эту ошибку при попытке получить соединение из пула:
springHikariCP - Соединение недоступно, время запроса истекло через 38268 мс. SQLState: 08S01. Код ошибки: 0.
Моя конфигурация HikariCP выглядит следующим образом:
//Set up connection pool
HikariConfig config = new HikariConfig();
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://dblocation");
//Connection pool properties
Properties prop = new Properties();
prop.setProperty("user", "Username");
prop.setProperty("password", "Password");
prop.setProperty("verifyServerCertificate", "false");
prop.setProperty("useSSL","true");
prop.setProperty("requireSSL","true");
config.setDataSourceProperties(properties);
config.setMaximumPoolSize(20);
config.setConnectionTestQuery("SELECT 1");
config.setPoolName("springHikariCP");
config.setLeakDetectionThreshold(5000);
config.addDataSourceProperty("dataSource.cachePrepStmts", "true");
config.addDataSourceProperty("dataSource.prepStmtCacheSize", "250");
config.addDataSourceProperty("dataSource.prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("dataSource.useServerPrepStmts", "true");
dataSource = new HikariDataSource(config);
Любая помощь будет принята с благодарностью.
connection.isValid(int)
надежен. Ваш комментарий подразумевает, что использование пула соединений потенциально может устранить подобные детали низкого уровня - так ли это на самом деле? - person JackB   schedule 02.02.2016HikariDataSource
расширяетHikariConfig
, что экономит вам некоторый код. - person M. Deinum   schedule 03.02.2016/* ping */ select 1
или только/* ping */
, так как это вызовет пинг вместо выполнения запроса. Может немного отличаться в поведении. - person M. Deinum   schedule 03.02.2016isValid
будет использоваться по умолчанию, если запрос не задан. - person M. Deinum   schedule 03.02.2016