简体   繁体   English

在Spring Boot中使用Hibernate SessionFactory进行连接泄漏

[英]Connection leak using Hibernate SessionFactory in Spring Boot

I have a Spring Boot (1.5.3) application in which I autowire the Hibernate (5.0.12) SessionFactory like this: 我有一个Spring Boot (1.5.3)应用程序,在其中我可以自动连接Hibernate (5.0.12) SessionFactory如下所示:

In application.properties : application.properties

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext

In the configuration class: 在配置类中:

@Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
    return new HibernateJpaSessionFactoryBean();
}

In the @Services : @Services

@Autowired
private SessionFactory sessionFactory;

This works well. 这很好。 But my problem is that after every request I get more and more idle PostgreSQL processes, and after a number of requests eventually I get this: 但是我的问题是,在每个请求之后,我都会得到越来越多的空闲PostgreSQL进程,并且在多次请求之后最终都得到了这个:

Caused by: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
...
Caused by: org.postgresql.util.PSQLException: FATAL: remaining connection slots are reserved for non-replication superuser connections
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
...
[ERROR] [16.05.17 20:19:39]               DirectJDKLog.java:181  Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; 
nested exception is javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431) ~[spring-orm-4.3.8.RELEASE.jar:4.3.8.RELEASE]
...
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
...
Caused by: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
...
Caused by: org.postgresql.util.PSQLException: FATAL: remaining connection slots are reserved for non-replication superuser connections
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
...
[ERROR] [16.05.17 20:19:39]               DirectJDKLog.java:181  Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction;
nested exception is javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431) ~[spring-orm-4.3.8.RELEASE.jar:4.3.8.RELEASE]
...
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
...
Caused by: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
...
Caused by: org.postgresql.util.PSQLException: FATAL: remaining connection slots are reserved for non-replication superuser connections
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
...
[ WARN] [16.05.17 20:19:40]         SqlExceptionHelper.java:127  SQL Error: 0, SQLState: 53300
[ERROR] [16.05.17 20:19:40]         SqlExceptionHelper.java:129  FATAL: remaining connection slots are reserved for non-replication superuser connections
[ERROR] [16.05.17 20:19:40]               DirectJDKLog.java:181  Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; 
nested exception is org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection] with root cause
org.postgresql.util.PSQLException: FATAL: remaining connection slots are reserved for non-replication superuser connections
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]

I use StatelessSession quite a bit for simple SQL queries, and I am 99.9% sure that I close them in the related @Service before returning the result. 对于简单的SQL查询,我经常使用StatelessSession ,并且我99.9%的确定在返回结果之前,请在相关的@Service关闭它们。

I have the unconfirmed feeling that with earlier Spring Boot versions, and the pulled-in dependencies, the problem did not exist. 不确定的感觉是,使用较早的Spring Boot版本以及引入的依赖关系,该问题不存在。 Not sure though... 不确定...

What could be the reason for these apparent leaks? 这些明显的泄漏可能是什么原因?

For completeness here some example uses in a @Service : 为了完整@Service这里在@Service使用了一些示例:

@Transactional(readOnly = true)
@Cacheable(value = "countries", key = "#root.methodName")
public List<Country> getCountries() {
    final StatelessSession session = sessionFactory.openStatelessSession();
    final Query query = session.createQuery("from Country order by id");
    final List<Country> result = query.list();
    session.close();
    return result;
}

@Transactional(readOnly = true)
public long countTimeZones() {
    final StatelessSession session = sessionFactory.openStatelessSession();
    final Long result = (Long) session.createQuery("select count(o) from TimeZone o").uniqueResult();
    session.close();
    return result;
}

@Transactional(readOnly = true)
public List<Map<String, Object>> getPhotoAlbums() {
    final StatelessSession session = sessionFactory.openStatelessSession();
    final SQLQuery query = session.createSQLQuery("select "
            + "cast(m.id as varchar), "
            + "m.name "
            // etc
            + "from media_album m "
            + "where m.account = :account "
            + "and ... "
            + "order by ...");
    query.setParameter("account", uuidOfAccount);
    query.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
    final List<Map<String, Object>> result = query.list();
    session.close();
    return result;
}

I could "solve" the leaks by changing the configuration like follows (Not sure all these steps are necessary though): 我可以通过如下更改配置来“解决”泄漏(尽管不确定所有这些步骤是否必要):

application.properties: application.properties:

spring.jpa.properties.hibernate.current_session_context_class=
org.springframework.orm.hibernate5.SpringSessionContext

Configuration class: 配置类:

add @EnableAutoConfiguration , as well as: 添加@EnableAutoConfiguration ,以及:

@Bean
public HibernateJpaSessionFactoryBean sessionFactory(EntityManagerFactory emf) {
    HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
    factory.setEntityManagerFactory(emf);
    return factory;
}

This answer was helpful: 这个答案很有帮助:

required a bean of type 'org.hibernate.SessionFactory' that could not be found 需要找不到类型为“ org.hibernate.SessionFactory”的bean

I believe you need to set the following property: 我相信您需要设置以下属性:

spring.datasource.max-active

eg spring.datasource.max-active=5 例如spring.datasource.max-active=5

It looks as though the spring connection pool is opening more connections than is allowed in your postgresql.conf file 看起来Spring连接池正在打开的连接超出了postgresql.conf文件所允许的数量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM