【问题标题】:Unable to acquire JDBC Connection无法获取 JDBC 连接
【发布时间】:2017-11-09 01:34:00
【问题描述】:

我有一个带有 Hibernate 和 Hikari 数据源的 Spring Boot 项目。 如果我有一些注入 SessionFactory 对象的功能来获取会话对象,那么几天后我对与 db 操作相关的任何方法都有这样的异常(只有重新启动才能解决这个问题):

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.

似乎手动使用会话会导致此问题。 (我有类似的项目,具有相同的配置和功能,但没有注入 SessionFactory 和 Session ......我根本没有这样的问题)

application.yaml

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

数据源配置

@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();没解决这个问题

【问题讨论】:

  • 它是否适用于初始操作,但在一些成功的选择/保存后开始超时?
  • 是的,第一次启动应用后,一切正常。
  • 我知道时间已经过去了,但这是怎么结束的?

标签: hibernate spring-boot hikaricp


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    在我看来,您的事务边界存在问题,它没有将连接释放回池。您可以尝试将@Transactional 放在您的LogRepositoryImpl 课程中吗?

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

    【讨论】:

    • 我不直接使用 LogRepositoryImpl。我有 LogService 及其实现注解 @Transactional 注入 logRepository
    • 啊,根据您问题中的信息,不可能知道这一点。您是否在高度并发的环境中运行?如果您的应用一次需要大量连接,您可以尝试增加池大小。
    • 这对我来说意味着您的应用程序中肯定有一些操作不会将连接释放回池。你在其他地方使用数据源吗?
    • 我遇到了完全相同的问题,每天我都必须重新启动服务器,这让我发疯了!我无法弄清楚泄漏!
    • 添加 com.zaxxer.hikari:DEBUG 日志级别,将添加 pg-pool - 池统计信息(total=100,active=0,idle=100,waiting=0)连接日志
    猜你喜欢
    • 2017-08-02
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-09-03
    • 2019-04-18
    • 2020-11-06
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多