我创建了一个简单的程序,它重复创建与数据库的连接,然后关闭该连接。程序在第六次或第七次迭代时产生错误。如果我在每次迭代之间将程序暂停五秒钟,则程序在第三次迭代时会产生错误。 打印出连接状态表明它们已成功关闭,因此不应发生连接泄漏。我的连接是通过 HikariCP 和 Google Cloud 的 IAM 身份验证建立的。
package Tester;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import InstanceCreator.InstanceCreator;
public class Tester {
public static void main(String[] args) throws SQLException, InterruptedException {
int i = 1;
while (true) {
System.out.println("Starting loop: " + i);
i++;
Thread.sleep(5000);
DataSource dataSource = InstanceCreator.createConnectionPool();
Connection connection = null;
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
finally {
connection.close();
}
}
}
}
package InstanceCreator;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
public class InstanceCreator {
private static final String INSTANCE_CONNECTION_NAME = "mycreds";
private static final String DB_IAM_USER = "mycreds";
private static final String DB_NAME = "mycreds";
public static DataSource createConnectionPool() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(String.format("jdbc:postgresql:///%s", DB_NAME));
config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.postgres.SocketFactory");
config.addDataSourceProperty("cloudSqlInstance", INSTANCE_CONNECTION_NAME);
config.addDataSourceProperty("enableIamAuth", "true");
config.addDataSourceProperty("user", DB_IAM_USER);
config.addDataSourceProperty("password", "password");
config.addDataSourceProperty("sslmode", "disable");
return new HikariDataSource(config);
}
}
Starting loop: 1
SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
Starting loop: 2
Starting loop: 3
Starting loop: 4
Starting loop: 5
Starting loop: 6
Starting loop: 7
Exception in thread "main" com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: FATAL: remaining connection slots are reserved for non-replication superuser connections
at com.zaxxer.hikari.pool.HikariPool.throwPoolInitializationException(HikariPool.java:596)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:582)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81)
at InstanceCreator.InstanceCreator.createConnectionPool(InstanceCreator.java:27)
at Tester.Tester.main(Tester.java:17)
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:2676)
at org.postgresql.core.v3.QueryExecutorImpl.readStartupMessages(QueryExecutorImpl.java:2788)
at org.postgresql.core.v3.QueryExecutorImpl.<init>(QueryExecutorImpl.java:174)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:313)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:54)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:253)
at org.postgresql.Driver.makeConnection(Driver.java:434)
at org.postgresql.Driver.connect(Driver.java:291)
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:121)
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:364)
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206)
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:476)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561)
... 4 more
每次在循环中,您创建的不是一个连接,而是一个连接池。默认情况下,一个 HikariCP 池打开 10 个到数据库的连接,因此在第六次迭代时有 60 个活动连接,而在第七次迭代时已经有 70 个。任何 DBMS 都对最大连接数有限制;在 PostgreSQL 中默认为 100。创建大量连接后,您很快就耗尽了此限制并收到错误 org.postgresql.util.PSQLException: FATAL: 剩余连接槽保留用于非复制超级用户连接。 PostgreSQL 保留三个连接用于管理目的,以便主管即使在连接限制耗尽时也可以连接到 DBMS。不要这样做,谨慎使用连接。