【问题标题】:Getting too many connection for role when using DataSource使用 DataSource 时获得过多的角色连接
【发布时间】:2023-03-11 11:29:02
【问题描述】:

我有一个 Rest 服务,当它得到它时,它必须对近 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 不需要关闭,因为它永远不会打开。

注意:

DataSource 实现不需要关闭,因为它永远不会关闭 “打开”DataSource 不是资源,未连接到 数据库,因此它没有保持网络连接或资源 数据库服务器。 DataSource 只是在以下情况下需要的信息 建立与数据库的连接,使用数据库服务器的 网络名称或地址、用户名、用户密码和各种 您希望在最终建立连接时指定的选项。

谁能告诉我为什么会遇到这个问题

【问题讨论】:

    标签: spring-boot java-8 datasource jdbctemplate


    【解决方案1】:

    问题出在 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();
            }
        }
    });
    

    【讨论】:

    • 但是连接池确实很好,因为池会处理连接,而不是每次都创建一个新的连接
    • 是的,但它会产生一些初始连接数并保持它们运行。尝试减少连接数或使用 SingleConnectionDataSource。在您的情况下,一个连接就足够了。
    • 但这是一个休息服务,每 30 分钟调用一次,所以你认为池化不会是一个更好的解决方案。
    • 这对您的情况很好,因为每个数据库有足够的一个连接来执行所有查询。您不需要生成多个。
    • 是的,您需要确保关闭连接。
    【解决方案2】:

    首先,让单个应用程序管理 50 个数据库是非常糟糕的架构决策。无论如何,不​​要在 for 循环中创建 DataSource,您应该使用工厂设计模式为每个 DB 创建 DataSource。您应该为您的系统添加一些连接池机制。 HijariCP 和 TomcatPool 使用最广泛。分析故障线程日志以了解任何进一步的问题。

    【讨论】:

    • 请参阅下面关于 DataSourceBuilder 的评论。有池不释放资源的问题。
    猜你喜欢
    • 2020-06-05
    • 1970-01-01
    • 2018-03-18
    • 2020-12-17
    • 1970-01-01
    • 2014-09-23
    • 2022-11-11
    • 2021-08-19
    • 1970-01-01
    相关资源
    最近更新 更多