Я работаю с data-envers над своим Spring-Boot проектом в среде разработки.
Когда микросервис проработает примерно 8 часов, соединение с базой данных перестанет работать (продолжают работать только те запросы, которые используются с data-envers, то есть любой запрос с JPA, например).
Каждый раз, когда я перезапускаю микросервис (pod), соединение с базой данных снова работает, и запросы, сделанные с помощью data-envers, снова работают (еще около 8 часов).
Я прочитал много статей и сообщений о SO, но они мне не помогли. Я добавил в свой файл .yml следующие свойства:
testOnBorrow : true
validationQuery : SELECT 1
я также добавил
url: jdbc:mysql://localhost:3306/mydatabase?autoReconnect=true
и не могу переподключиться.
Обновил версию Hikari, так как тоже читал, что может быть так, но это не так.
Моя data-envers версия 2.7.6
Любые идеи, как предотвратить закрытие или автоматическое повторное подключение соединения?
Это мой .yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mydatabase?autoReconnect=true
username: X
password: X
testOnBorrow : true
validationQuery : SELECT 1
hikari:
connection-timeout: 20000
maximum-pool-size: 5
и трассировка стека:
java.sql.SQLException: Connection is closed
at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection$0(ProxyConnection.java:515) ~[HikariCP-5.0.0.jar!/:na]
at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection$$Lambda$718/0x00000000558ea900.invoke(Unknown Source) ~[na:na]
at com.sun.proxy.$Proxy105.prepareStatement(Unknown Source) ~[na:na]
at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:337) ~[HikariCP-5.0.0.jar!/:na]
at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) ~[HikariCP-5.0.0.jar!/:na]
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:149) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:151) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:2122) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2059) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2037) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:956) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:357) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2868) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2850) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2682) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.Loader.list(Loader.java:2677) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:540) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1459) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1649) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1617) ~[hibernate-core-5.6.12.Final.jar!/:5.6.12.Final]
at org.hibernate.envers.query.internal.impl.AbstractAuditQuery.buildAndExecuteQuery(AbstractAuditQuery.java:106) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.RevisionsOfEntityQuery.getQueryResults(RevisionsOfEntityQuery.java:173) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.RevisionsOfEntityQuery.list(RevisionsOfEntityQuery.java:136) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.AbstractAuditQuery.getResultList(AbstractAuditQuery.java:112) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
Есть еще одна трассировка стека:
com.mysql.cj.jdbc.exceptions.CommunicationsException: The last packet successfully received from the server was 35,850,470 milliseconds ago. The last packet sent successfully to the server was 35,850,472 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) ~[mysql-connector-java-8.0.28.jar!/:8.0.28]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-java-8.0.28.jar!/:8.0.28]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.28.jar!/:8.0.28]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1009) ~[mysql-connector-java-8.0.28.jar!/:8.0.28]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-4.0.3.jar!/:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar!/:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.getResultSet(Loader.java:2322) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2075) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2037) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:956) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:357) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2868) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2850) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2682) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.Loader.list(Loader.java:2677) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:540) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1459) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1649) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1617) ~[hibernate-core-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.AbstractAuditQuery.buildAndExecuteQuery(AbstractAuditQuery.java:106) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.RevisionsOfEntityQuery.getQueryResults(RevisionsOfEntityQuery.java:173) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.RevisionsOfEntityQuery.list(RevisionsOfEntityQuery.java:136) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
at org.hibernate.envers.query.internal.impl.AbstractAuditQuery.getResultList(AbstractAuditQuery.java:112) ~[hibernate-envers-5.6.8.Final.jar!/:5.6.8.Final]
ОБНОВЛЕНО:
Это мой сервис, который использует auditQuery
public List<Revision> getRevisions(Integer id) {
AuditQuery auditQuery = null;
List<Revision> revisionList = new ArrayList<Revision>();
//Find all modifications
try {
auditQuery = auditReader.createQuery()
.forRevisionsOfEntityWithChanges(MyEntity.class, true)
.addOrder(AuditEntity.revisionNumber().desc());
}
catch (Exception exception) {
log.error("Can not get revisions. Return empty list without revisions.");
log.error(exception.getMessage());
return new ArrayList<Revision>();
}
List<Object[]> result = auditQuery.getResultList();
Последняя строка - это когда я получаю сообщение об ошибке при закрытии соединения.
И это класс конфигурации
@Configuration
public class AuditConfiguration {
private final EntityManagerFactory entityManagerFactory;
AuditConfiguration(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@Bean
AuditReader auditReader() {
return AuditReaderFactory.get(entityManagerFactory.createEntityManager());
}
}




основываясь на ваших трассировках стека, я бы сказал, что основная причина находится где-то в вашем приложении.
I. Следующие настройки не влияют на опрос подключения hikari:
testOnBorrow : true
validationQuery : SELECT 1
эти настройки действительны для Пула соединений JDBC Tomcat, обратите внимание, что префикс конфигурации для этих настроек должен быть spring.datasource.tomcat.
если вам нужно настроить запрос проверки для hikari пула соединений, допустимым параметром конфигурации является spring.datasource.hikari.connection-test-query, однако в большинстве случаев это не требуется, более того, hikari автор настоятельно не рекомендует использовать эту функцию:
Если ваш драйвер поддерживает JDBC4, мы настоятельно рекомендуем не устанавливать это свойство. Это для «устаревших» драйверов, которые не поддерживают JDBC4
Connection.isValid()API. Это запрос, который будет выполняться непосредственно перед тем, как вам будет предоставлено соединение из пула, чтобы проверить, что соединение с базой данных все еще активно. Опять же, попробуйте запустить пул без этого свойства, HikariCP зарегистрирует ошибку, если ваш драйвер не совместим с JDBC4, чтобы сообщить вам об этом. По умолчанию: нет
II. вы также не должны использовать autoReconnect=true :
Должен ли драйвер пытаться восстановить устаревшие и/или мертвые соединения? Если этот параметр включен, драйвер выдает исключение для запросов, отправленных по устаревшему или мертвому соединению, которые относятся к текущей транзакции, но попытается переподключиться до того, как следующий запрос будет отправлен для соединения в новой транзакции. Использование этой функции не рекомендуется, поскольку она имеет побочные эффекты, связанные с состоянием сеанса и согласованностью данных, когда приложения не обрабатывают исключения SQLException должным образом, и предназначена для использования только в том случае, если вы не можете настроить свое приложение для обработки исключений SQLException, возникающих в результате мертвые и устаревшие соединения должным образом. В качестве альтернативы, в качестве последнего варианта, попробуйте установить для переменной сервера MySQL 'wait_timeout' высокое значение, а не значение по умолчанию, равное 8 часам.
III. внимательно посмотрите на следующую трассировку стека:
java.sql.SQLException: Connection is closed
at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection$0(ProxyConnection.java:515) ~[HikariCP-5.0.0.jar!/:na]
at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection$$Lambda$718/0x00000000558ea900.invoke(Unknown Source) ~[na:na]
at com.sun.proxy.$Proxy105.prepareStatement(Unknown Source) ~[na:na]
обратите внимание, что исключение было выдано в классе com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection, hikari заменяет реальный экземпляр соединения jdbc прокси-сервером на основе com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection, когда соединение JDBC либо закрывается , либо получает фатальную ошибку, таким образом, определенно ясно, что ваше приложение продолжает использовать JDBC соединение после того, как оно было закрыто или получить фатальную ошибку
УПД.
Ну, теперь понятно, что происходит. Конфигурация ниже:
@Configuration
public class AuditConfiguration {
private final EntityManagerFactory entityManagerFactory;
AuditConfiguration(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@Bean
AuditReader auditReader() {
return AuditReaderFactory.get(entityManagerFactory.createEntityManager());
}
}
создает один экземпляр EntityManager для всего приложения и привязывает его к одному экземпляру AuditReader, поэтому вы никогда не освобождаете базовое соединение JDBC с пулом и не получаете эти глупые ошибки.
Быстрое решение состоит в том, чтобы удалить эту преждевременную оптимизацию и переписать класс обслуживания, что-то вроде (здесь я полагаю, что EMF управляется spring):
@Autowired
private EntityManager entityManager;
@Transactional
public List<Revision> getRevisions(Integer id) {
AuditReader auditReader = AuditReaderFactory.get(entityManager);
AuditQuery auditQuery = null;
List<Revision> revisionList = new ArrayList<Revision>();
трудно сказать, так как вы не делитесь кодом
Я обновил сообщение с моим сервисом и кодом конфигурации. Пожалуйста, скажите мне, если вам нужно что-то еще
@Talenel, пожалуйста, проверьте UPD.
большое спасибо, я попробую это решение, если это сработает, я проверю это, чтобы получить правильный ответ, но мне нужно подождать не менее 8 часов, чтобы увидеть, работает ли
хорошо, я понимаю, но что я могу сделать, чтобы решить эту проблему?