重写DataSource Bean后数据库连接频繁关闭,如何恢复正常行为?
问题根源与解决方案
你的核心问题有两个:一是手动创建的ExtendedHikariDataSource未配置连接池核心参数,二是配置类中创建Bean时直接调用其他@Bean方法,导致多个Bean实例使用不同的DataSource/EntityManagerFactory,破坏了Spring的连接池管理逻辑。以下是具体修复步骤:
1. 正确配置HikariDataSource连接池参数
直接new ExtendedHikariDataSource()不会加载Spring Boot默认的连接池配置,必须手动设置必要参数,让连接池能复用连接而非用完即关闭:
@Configuration @ConfigurationProperties(prefix = "spring.datasource") // 读取Spring Boot默认数据源配置 public class DataSourceConfiguration { @Value("${spring.datasource.url}") private String jdbcUrl; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Value("${spring.datasource.hikari.minimum-idle:5}") private int minimumIdle; @Value("${spring.datasource.hikari.maximum-pool-size:10}") private int maximumPoolSize; @Bean public DataSource dataSource() { ExtendedHikariDataSource dataSource = new ExtendedHikariDataSource(); dataSource.setJdbcUrl(jdbcUrl); dataSource.setUsername(username); dataSource.setPassword(password); // 核心连接池参数,控制连接复用 dataSource.setMinimumIdle(minimumIdle); dataSource.setMaximumPoolSize(maximumPoolSize); dataSource.setConnectionTimeout(30000); // 连接超时时间 dataSource.setIdleTimeout(600000); // 连接空闲超时时间 return dataSource; } // ... 其他Bean }
2. 修正Bean依赖注入方式,避免重复创建实例
当前配置中,entityManagerFactory()直接调用dataSource()、transactionManager()直接调用entityManagerFactory().getObject(),会导致每次调用都创建新实例,而非复用Spring容器中的单例Bean。必须通过方法参数注入获取已管理的Bean:
@Bean // 注入Spring管理的DataSource单例Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { Map<String, String> jpaProperties = new HashMap<>(); jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); jpaProperties.put(TransactionSettings.AUTO_CLOSE_SESSION, "false"); jpaProperties.put(MappingSettings.PHYSICAL_NAMING_STRATEGY, "..."); // 保持默认的连接释放模式,无需手动设置 // jpaProperties.put("hibernate.connection.release_mode", "auto"); return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), jpaProperties, null) .dataSource(dataSource) // 使用注入的DataSource .packages("org.mypackage") .build(); } @Bean // 注入Spring管理的EntityManagerFactoryBean public PlatformTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject()); return transactionManager; } @Bean // 注入Spring管理的DataSource单例Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); }
3. 检查Hibernate连接释放模式
不要设置hibernate.connection.release_mode为after_statement,该参数会让Hibernate在每个SQL语句执行后立即关闭连接。保持默认的auto即可,它会根据事务上下文自动管理连接释放(事务结束后归还到连接池)。
4. 验证连接池行为
修复后,可添加HikariCP日志配置观察连接流转:
logging.level.com.zaxxer.hikari=DEBUG
执行测试时,日志中应能看到连接被borrowed(借出)和returned(归还)到池里,而非直接关闭。
内容的提问来源于stack exchange,提问作者JayDesAt
相关产品推荐
相关产品推荐

