无法获取JDBC连接

37

我有一个使用Hibernate和Hikari DataSource的Spring Boot项目。如果我有一些功能需要注入SessionFactory对象来获取会话对象,在几天内,所有与数据库操作相关的方法都会出现异常(只有重新启动才能解决此问题):

org.springframework.transaction.CannotCreateTransactionException: 
Could not open JPA EntityManager for transaction; nested exception is 
javax.persistence.PersistenceException: 
org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection at
......
Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - 
Connection is not available, request timed out after 30001ms.

看起来是手动使用session引起了这个问题。(我有一个类似的项目,具有相同的配置和功能,但没有注入SessionFactory和Session...而且我根本就没有这样的问题)

application.yaml:

spring:
  jpa:
    properties:
      hibernate:
        dialect : org.hibernate.dialect.PostgreSQLDialect
        current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext

DataSourceConfig

的翻译是:

数据源配置

@EnableJpaRepositories("com.my.project.config")
@Configuration
public class DataSourceConfig {

    @Inject
    private AppProperties properties;

    @Bean(name = "dataSource")
    public DataSource dataSource() {
        AppProperties.DatabaseProperties dbProps = properties.getDatabaseProperties();
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(org.postgresql.Driver.class.getName());
        dataSource.setJdbcUrl(
            dbProps.getProtocol().concat("://")
                .concat(dbProps.getDbHost()).concat(":")
                .concat(dbProps.getDbPort()).concat("/")
                .concat(dbProps.getDbname())
        );
        dataSource.setUsername(dbProps.getUsername());
        dataSource.setPassword(dbProps.getPassword());
        dataSource.setMaximumPoolSize(30);
        dataSource.setMinimumIdle(30);

        return dataSource;
    }

    @Bean
    public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf)   {
        return hemf.getSessionFactory();
    }
}

LogRepositoryImpl

的翻译是

日志仓库实现

@Repository
public class LogRepositoryImpl implements LogRepository {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public List<Log> getLogs(int offset, int count) {
        Criteria criteria = getSession().createCriteria(Log.class);
        return criteria.setFirstResult(offset).setMaxResults(count).list();
    }

    @Override
    public void save(Log log) {
        getSession().save(log);
    }

    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }
}

dataSource.setMaximumPoolSize(30),dataSource.setMinimumIdle()并没有解决这个问题。


它在初始操作时是否有效,但在一些成功的选择/保存后开始超时? - Dean Clark
是的,在启动应用程序后的第一次使用中,一切都很好。 - Kiril Mytsykov
6
我知道时间已经过去了,但这是怎么结束的? - afe
2个回答

15

我们最近遇到了这个问题,但连接池错误信息最终只是引诱。

真正的问题是一个第三方系统不接受更多的消息,从而阻塞了每个线程。如果线程之前从HikariCP获取了连接,则连接永远不会返回到池中。因此,我们有与池连接数相同数量的成功连接。

在这种情况下:使用一个选择的工具(任何APM、VisualVM或类似工具)检查JVM上被阻塞的线程数量,并使用线程转储查看阻塞线程停留的位置。


5

听起来像是您的事务边界有问题,无法将连接释放回池中。您可以尝试在LogRepositoryImpl类上加上@Transactional注解吗?

@Repository
@Transactional
public class LogRepositoryImpl implements LogRepository {
    . . . 
}

我并不直接使用 LogRepositoryImpl。我有一个被注解为@Transactional的LogService及其实现,其中注入了logRepository。 - Kiril Mytsykov
啊,根据你的问题描述无法得知这些信息。你是在高并发环境下运行吗?如果你的应用程序需要大量连接,可以尝试增加连接池大小。 - Dean Clark
1
这对我来说意味着你的应用程序中肯定有一些操作没有将连接释放回池中。你在其他地方使用数据源吗? - Dean Clark
2
我有完全相同的问题,每天都要重新启动服务器,这让我疯狂!我想不出漏洞在哪里! - Ronny Shibley
1
添加 com.zaxxer.hikari: DEBUG 日志级别,这将添加 pg-pool - 池统计信息 (总数=100,活动中=0,空闲中=100,等待中=0) 的连接日志。 - NIrav Modi
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接