在 ASP.NET Core 3.1 中使用多个 connectionString DI NpgsqlConnection postgreSQL 的正确方法

The right way to DI NpgsqlConnection postgreSQL with multiple connectionString in ASP.NET Core 3.1

我正在努力使用 ASP.NET Core 3.1Dapper v2.0.78Postgres v11 中的多个连接字符串注册 DI NpgsqlConnection()

我将提供当前状态并修复以下代码:

当前状态

想法来自here

步骤 1Startup.cs --> ConfigureServices()

services.AddTransient<IDbConnectionFactory, DapperDbConnectionFactory>(sp =>
{
  var connectionDict = new Dictionary<DatabaseConnectionName, string>
  {
     { DatabaseConnectionName.Cnn1, "Connectionstring 1"},
     { DatabaseConnectionName.Cnn2, "Connectionstring 2"}
  };
  return new DapperDbConnectionFactory(connectionDict);
});

步骤 2DapperDbConnectionFactory 看起来像这样:

public class DapperDbConnectionFactory : IDbConnectionFactory
{
    private readonly IDictionary<DatabaseConnectionName, string> _connectionDict;

    public DapperDbConnectionFactory(IDictionary<DatabaseConnectionName, string> connectionDict)
    {
        _connectionDict = connectionDict;
    }

    public IDbConnection CreateDbConnection(DatabaseConnectionName connectionName)
    {
        string connectionString = null;

        if (_connectionDict.TryGetValue(connectionName, out connectionString))
        {
            return new NpgsqlConnection(connectionString); // <--- I think the issue comes from here
        }

        throw new ArgumentNullException();
    }
}

步骤 3:我使用这段代码的方式:

public ConstructorMedthod(IDbConnectionFactory _connFactory)
{
   _conn = _connFactory.CreateDbConnection(DatabaseConnectionName.Cnn1);
}
public async Task<QueryResult<IBaseReportModel>> Handle(...)
{
 ...
   var query = await _conn.QueryMultipleAsync("Query content here"); // <--- I think the issue comes from here
 ...
}

我确实认为使用方式不正确,需要在 using 语句中包装调用 _conn.QueryMultipleAsync 至少以确保连接已关闭并处理 return连接池。因为 DI 容器只是管理 DapperDbConnectionFactory 的生命周期而不是 IDbConnection

因此,有时我会收到此错误:

Npgsql.NpgsqlException (0x80004005): The connection pool has been exhausted, either raise MaxPoolSize (currently 100) or Timeout (currently 15 seconds)

我必须重新启动应用程序才能恢复正常。所以我不确定问题是 max connection pool 还是 Timeout 由于网络。它应该能够检查池中的连接数与当时最大连接池的比较。我假设。

修复代码

我有两个想法:

  1. 将调用 _conn.QueryMultipleAsync 包装在 using 语句中。但是这样我不得不在调用 _conn.

    的任何地方更改太多代码
  2. 改成DI方式(思路来自)。更多详情如下。

步骤 1Startup.cs --> ConfigureServices()

services.AddTransient<ServiceResolver>(serviceProvider => cnn_Name =>
{
    switch (cnn_Name)
    {
        case "Cnn1":
            return new NpgsqlConnection("Connectionstring 1");
        case "Cnn2":
            return new NpgsqlConnection("Connectionstring 2");
        default:
            throw new KeyNotFoundException();
    }
});

public delegate IDbConnection ServiceResolver(string connectionstring);

第二步:我的使用方式:

private readonly IDbConnection _conn;

public ConstructorMedthod(ServiceResolver serviceAccessor)
{
   _conn = serviceAccessor(DbConnectionKey.Cnn1);
}

public async Task<QueryResult<IBaseReportModel>> Handle(...)
{
 ...
   var query = await _conn.QueryMultipleAsync("Query content here"); 
   // Now I suppose the _conn will be closed & disposed by DI container.
 ...
}

问题

  1. 在 ASP.NET Core 3.1 中使用多个连接字符串注册 postgreSQL 的 DI NpgsqlConnection 的正确方法是什么?

  2. 我如何验证连接字符串是 returned 连接池,就像 Query on PostgreSQLthis and this one

SELECT * FROM pg_stat_activity;
  1. 如何将 max connection pool 增加到大于 100。这是否是最佳做法?我发现 post 说

Just increasing max_connections is bad idea. You need to increase shared_buffers and kernel.shmmax as well.

其实我用的是AWS的RDS PostgreSQL。所以我想这样配置 appsettings

UserID=root;Password=myPassword;Host=localhost;Port=5432;Database=myDataBase;Pooling=true;Minimum Pool Size=0;Maximum Pool Size=200;

此外,正如post所说

Npgsql connection pooling is implemented inside your application process - it has nothing to do with PostgreSQL, which is completely unaware of it.

所以我非常混淆 PostgreSQL(问题 #2)和 Appsettings(问题 #3)

之间的最大连接池

不幸的是, author of the current state solution

I am not sure if I am using the best practices correctly or not, but I am doing it this way, in order to handle multiple connection strings.

非常详细地阅读评论后,我认识到你必须像这样使用using语句

public async Task<QueryResult<IBaseReportModel>> Handle(...)
{
 ...
     using(var conn = _connFactory.CreateDbConnection(DatabaseConnectionName.Cnn1))
     {
       var response = await conn.QueryMultipleAsync("Query content here");
     }
 ...
}

否则,你会得到这个错误

Npgsql.NpgsqlException (0x80004005): The connection pool has been exhausted, either raise MaxPoolSize (currently 100) or Timeout (currently 15 seconds)

"53300: remaining connection slots are reserved for non-replication superuser connections"

突出显示的评论在下方。希望能帮助大家避免隐藏的错误。

已更新 - 2022-05-13

来自 answer, we already have clarified the - 问题 #3Appsetings -> Maximum Pool Size=200;PostgreSQL --> SHOW max_connections;

之间