使用 DataSource 时为角色获取太多连接
Getting too many connection for role when using DataSource
我有一个休息服务,当它获得时,它必须对近 25 个数据库进行一些插入和更新。所以当我像下面的代码一样尝试时,它在我的本地主机上工作但是当我部署到我的登台服务器时我得到 FATAL: too many connections for role "user123"
List<String> databaseUrls = null;
databaseUrls.forEach( databaseUrl -> {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName("org.postgresql.Driver")
.url(databaseUrl)
.username("user123")
.password("some-password")
.build();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("Some...Update...Query");
});
根据我的理解 DataSource 不需要关闭,因为它从未打开过。
注:
A DataSource implementation need not be closed, because it is never
“opened”. A DataSource is not a resource, is not connected to the
database, so it is not holding networking connections nor resources on
the database server. A DataSource is simply information needed when
making a connection to the database, with the database server's
network name or address, the user name, user password, and various
options you want specified when a connection is eventually made.
谁能告诉我为什么会遇到这个问题
问题出在 DataSourceBuilder 中,它实际上创建了连接池,该连接池产生了一定数量的连接并保留它们 运行:
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"org.apache.tomcat.jdbc.pool.DataSource",
"com.zaxxer.hikari.HikariDataSource",
"org.apache.commons.dbcp.BasicDataSource" };
Javadoc 说:
/**
* Convenience class for building a {@link DataSource} with common implementations and
* properties. If Tomcat, HikariCP or Commons DBCP are on the classpath one of them will
* be selected (in that order with Tomcat first). In the interest of a uniform interface,
* and so that there can be a fallback to an embedded database if one can be detected on
* the classpath, only a small set of common configuration properties are supported. To
* inject additional properties into the result you can downcast it, or use
* <code>@ConfigurationProperties</code>.
*/
尝试使用例如SingleConnectionDataSource,那么你的问题就解决了:
List<String> databaseUrls = null;
Class.forName("org.postgresql.Driver");
databaseUrls.forEach( databaseUrl -> {
SingleConnectionDataSource dataSource;
try {
dataSource = new SingleConnectionDataSource(
databaseUrl, "user123", "some-password", true /*suppressClose*/);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("Some...Update...Query");
} catch (Exception e) {
log.error("Failed to run queries for {}", databaseUrl, e);
} finally {
// release resources
if (dataSource != null) {
dataSource.destroy();
}
}
});
首先,让单个应用程序管理 50 个数据库是非常糟糕的架构决策。无论如何,您应该使用工厂设计模式为每个数据库创建数据源,而不是在 for 循环中创建数据源。您应该向您的系统添加一些连接池机制。 HijariCP 和 TomcatPool 使用最广泛。分析失败线程的日志以查找任何其他问题。
我有一个休息服务,当它获得时,它必须对近 25 个数据库进行一些插入和更新。所以当我像下面的代码一样尝试时,它在我的本地主机上工作但是当我部署到我的登台服务器时我得到 FATAL: too many connections for role "user123"
List<String> databaseUrls = null;
databaseUrls.forEach( databaseUrl -> {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName("org.postgresql.Driver")
.url(databaseUrl)
.username("user123")
.password("some-password")
.build();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("Some...Update...Query");
});
根据我的理解 DataSource 不需要关闭,因为它从未打开过。
注:
A DataSource implementation need not be closed, because it is never “opened”. A DataSource is not a resource, is not connected to the database, so it is not holding networking connections nor resources on the database server. A DataSource is simply information needed when making a connection to the database, with the database server's network name or address, the user name, user password, and various options you want specified when a connection is eventually made.
谁能告诉我为什么会遇到这个问题
问题出在 DataSourceBuilder 中,它实际上创建了连接池,该连接池产生了一定数量的连接并保留它们 运行:
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"org.apache.tomcat.jdbc.pool.DataSource",
"com.zaxxer.hikari.HikariDataSource",
"org.apache.commons.dbcp.BasicDataSource" };
Javadoc 说:
/**
* Convenience class for building a {@link DataSource} with common implementations and
* properties. If Tomcat, HikariCP or Commons DBCP are on the classpath one of them will
* be selected (in that order with Tomcat first). In the interest of a uniform interface,
* and so that there can be a fallback to an embedded database if one can be detected on
* the classpath, only a small set of common configuration properties are supported. To
* inject additional properties into the result you can downcast it, or use
* <code>@ConfigurationProperties</code>.
*/
尝试使用例如SingleConnectionDataSource,那么你的问题就解决了:
List<String> databaseUrls = null;
Class.forName("org.postgresql.Driver");
databaseUrls.forEach( databaseUrl -> {
SingleConnectionDataSource dataSource;
try {
dataSource = new SingleConnectionDataSource(
databaseUrl, "user123", "some-password", true /*suppressClose*/);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("Some...Update...Query");
} catch (Exception e) {
log.error("Failed to run queries for {}", databaseUrl, e);
} finally {
// release resources
if (dataSource != null) {
dataSource.destroy();
}
}
});
首先,让单个应用程序管理 50 个数据库是非常糟糕的架构决策。无论如何,您应该使用工厂设计模式为每个数据库创建数据源,而不是在 for 循环中创建数据源。您应该向您的系统添加一些连接池机制。 HijariCP 和 TomcatPool 使用最广泛。分析失败线程的日志以查找任何其他问题。