启动生成6个Hikari连接池及测试数据库客户端过多问题求助
问题解决:Hikari连接池数量异常与PostgreSQL连接数超限
一、启动时创建6个Hikari连接池的原因及解决方法
原因分析
- 数据源方法未被Spring管理为单例Bean:
masterDataSource()和readonlyDataSource()没有添加@Bean注解,导致每次调用这两个方法时,都会执行方法体生成全新的数据源对象,而非复用已创建的实例。 - 单数据源方法内重复创建连接池:在
masterDataSource()和readonlyDataSource()中,先创建一个HikariDataSource实例,随后又将该实例传入connectionPoolDataSource(),通过HikariConfig再次创建新的HikariDataSource,等于每次调用数据源方法会生成2个独立的连接池。 - 数据源方法被多次调用:
dataSource()方法中,masterDataSource()被调用2次(一次加入targetDataSources,一次设为默认数据源),readonlyDataSource()被调用1次。结合前两点,总连接池数量为:2次master调用×2个池/次 + 1次readonly调用×2个池/次 = 6个,与日志完全匹配。
解决方法
修改数据源配置类,调整逻辑如下:
@Configuration @Getter @Setter public class DataSourcesConfiguration { @Autowired DataSourceConfig dataSourceConfig; private int minimumIdle = 0; private int maximumPoolSize = 4; private int keepaliveTime = 240000; @Bean public DataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("readonlyDataSource") DataSource readonlyDataSource) { RoutingDataSource masterSlaveRoutingDataSource = new RoutingDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.MASTER, masterDataSource); targetDataSources.put(DataSourceType.READONLY, readonlyDataSource); masterSlaveRoutingDataSource.setTargetDataSources(targetDataSources); log.info("Set default data source as master"); masterSlaveRoutingDataSource.setDefaultTargetDataSource(masterDataSource); return masterSlaveRoutingDataSource; } @Bean("readonlyDataSource") public DataSource readonlyDataSource() { log.info("Hit readonlyDataSource() data source"); HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(dataSourceConfig.getReadonlyUrl()); hikariConfig.setMinimumIdle(minimumIdle); hikariConfig.setMaximumPoolSize(maximumPoolSize); hikariConfig.setKeepaliveTime(keepaliveTime); return new HikariDataSource(hikariConfig); } @Primary @Bean("masterDataSource") public DataSource masterDataSource() { log.info("Hit masterDataSource() data source"); HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(dataSourceConfig.getMasterUrl()); hikariConfig.setMinimumIdle(minimumIdle); hikariConfig.setMaximumPoolSize(maximumPoolSize); hikariConfig.setKeepaliveTime(keepaliveTime); return new HikariDataSource(hikariConfig); } }
修改说明:
- 给两个数据源方法添加
@Bean注解并指定名称,通过@Qualifier注入单例实例,避免重复调用方法创建新对象; - 直接通过
HikariConfig配置并创建HikariDataSource,移除重复创建连接池的冗余逻辑,每个数据源仅生成1个连接池。
二、测试时PostgreSQL连接数超限(FATAL: sorry, too many clients already)的解决方法
原因分析
该错误是因为PostgreSQL的max_connections最大连接数设置,小于当前应用(含测试)占用的总连接数。测试场景下的常见诱因:
- 每个测试类启动独立Spring上下文,每个上下文创建2个连接池(主+只读),若
maximumPoolSize为4,多个测试类叠加后连接数快速耗尽; - 测试结束后Spring上下文未及时销毁,连接池未释放数据库连接;
- PostgreSQL默认
max_connections(通常为100)过小,无法支撑多测试用例的并发连接需求。
解决方法
- 复用Spring测试上下文:使用
@SpringBootTest时,确保相同配置的测试复用同一上下文,仅在必要时用@DirtiesContext刷新上下文,避免重复创建连接池。 - 降低测试环境连接池大小:在测试专用
application.yml中减小maximumPoolSize,例如:
spring: datasource: master: hikari: maximum-pool-size: 2 readonly: hikari: maximum-pool-size: 2
- 调整PostgreSQL最大连接数:修改
postgresql.conf配置文件,增大max_connections值:
max_connections = 200
修改后重启PostgreSQL生效。
4. 手动释放测试连接:在测试类的@AfterAll方法中,手动关闭数据源连接池,或依赖Spring上下文销毁时自动释放连接。
内容的提问来源于stack exchange,提问作者user19751568
相关产品推荐
相关产品推荐

