You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core+PostgreSQL遇too many connections for role错误求助

问题描述

在ASP.NET Core项目中使用PostgreSQL(ElephantSQL)和Entity Framework Core时,反复出现间歇性错误:

{"Message":"An error occurred while processing your request.","ExceptionMessage":"53300: too many connections for role "yxyjmsin"","ExceptionType":"Npgsql.PostgresException"}
{"Message":"An error occurred while processing your request.","ExceptionMessage":"An exception has been raised that is likely due to a transient failure.","ExceptionType":"System.InvalidOperationException"}

控制台输出的详细错误:

Severity: FATAL
SqlState: 53300
MessageText: too many connections for role "yxyjmsin"
File: miscinit.c
Line: 734
Routine: InitializeSessionUserId

已知角色yxyjmsin的连接数限制(rolconnlimit)为5,已尝试调整MaxBatchSize、启用重试机制,但问题未解决。现有配置代码如下:

Program.cs中的DbContext配置

builder.Services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
{
    var configuration = serviceProvider.GetRequiredService<IConfiguration>();
    var builder = new NpgsqlDataSourceBuilder(configuration.GetConnectionString("ElephantSQL"));
    options.UseNpgsql(builder.ConnectionString, npgsqlOptions => 
    {
        npgsqlOptions.EnableRetryOnFailure();
        npgsqlOptions.MaxBatchSize(5);
    });
    builder.MapEnum<UserRole>();
    builder.MapEnum<OrderStatus>();
    options.AddInterceptors(new TimeStampInterceptor());
    options.UseNpgsql(builder.Build()).UseSnakeCaseNamingConvention();
});

连接字符串配置

"ConnectionStrings": {
    "ElephantSQL": "Server=myServer;Port=5432;Username=yxyjmsin;Password=myPasswd;Database=myDb Pooling=true;"
 },

基础仓储的AddAsync方法

public async Task<TEntity> AddAsync(TEntity entity)
{
    try
    {
        if (entity is User userEntity)
        {
            if (userEntity.Role != UserRole.Admin)
            {
                userEntity.Role = UserRole.Customer;
            }
        }
        var entry = await _dbSet.AddAsync(entity);
        await _applicationDbContext.SaveChangesAsync();
        return entry.Entity;
    }
    catch (DbUpdateException ex)
    {                
        Console.WriteLine("Base Repository exception.");
        if (ex.InnerException != null)
        {
            Console.WriteLine("Inner exception: " + ex.InnerException.Message);
        }
        throw;
    }
}
解决方案

1. 修复DbContext的重复配置问题

代码中两次调用UseNpgsql会导致配置冲突,连接池设置无法正确生效。正确做法是用NpgsqlDataSourceBuilder构建完整数据源后,仅调用一次UseNpgsql:

builder.Services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
{
    var configuration = serviceProvider.GetRequiredService<IConfiguration>();
    var dataSourceBuilder = new NpgsqlDataSourceBuilder(configuration.GetConnectionString("ElephantSQL"));
    
    // 映射枚举
    dataSourceBuilder.MapEnum<UserRole>();
    dataSourceBuilder.MapEnum<OrderStatus>();
    
    // 构建数据源
    var dataSource = dataSourceBuilder.Build();
    
    // 配置EF Core
    options.UseNpgsql(dataSource, npgsqlOptions => 
    {
        npgsqlOptions.EnableRetryOnFailure();
        npgsqlOptions.MaxBatchSize(5);
    })
    .AddInterceptors(new TimeStampInterceptor())
    .UseSnakeCaseNamingConvention();
});

2. 配置连接池参数匹配角色连接限制

由于角色连接数限制为5,需在连接字符串中明确设置连接池最大连接数(建议设为4,留1个连接给非应用场景),同时添加优化参数:

"ConnectionStrings": {
    "ElephantSQL": "Server=myServer;Port=5432;Username=yxyjmsin;Password=myPasswd;Database=myDb;Pooling=true;Max Pool Size=4;Min Pool Size=0;Connection Lifetime=300;Idle Timeout=120;"
 },

参数说明:

  • Max Pool Size=4:连接池最大连接数,不超过角色限制
  • Connection Lifetime=300:连接在池中的最长存活时间(秒),到期自动销毁
  • Idle Timeout=120:空闲连接在池中保留的时间(秒),超时后释放

3. 确保DbContext和仓储的生命周期正确

  • AddDbContext默认注册为Scoped生命周期,这是DbContext的推荐配置,会在每个请求结束后自动释放连接。
  • 仓储类必须注册为Scoped(而非Singleton),避免单例仓储长期持有DbContext导致连接无法释放:
// 在Program.cs中注册仓储
builder.Services.AddScoped<IYourRepository, YourRepository>();

4. 排查长期持有DbContext的场景

如果项目存在以下情况,会导致连接被长期占用:

  • 在Singleton服务或后台任务中直接注入DbContext:改用IDbContextFactory<ApplicationDbContext>创建临时实例,使用完毕后释放:
    public class BackgroundServiceExample : BackgroundService
    {
        private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
    
        public BackgroundServiceExample(IDbContextFactory<ApplicationDbContext> contextFactory)
        {
            _contextFactory = contextFactory;
        }
    
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                using var context = _contextFactory.CreateDbContext();
                // 执行数据库操作
                await context.SaveChangesAsync(stoppingToken);
                await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
            }
        }
    }
    
  • 未使用async/await执行数据库操作:同步操作会阻塞连接,导致连接池无法及时回收。确保所有数据库操作都使用异步方法(如AddAsync、SaveChangesAsync)。

5. 检查未释放的事务

如果代码中使用了显式事务,确保事务最终被提交或回滚,避免连接被事务占用:

using var transaction = await _applicationDbContext.Database.BeginTransactionAsync();
try
{
    // 执行操作
    await _applicationDbContext.SaveChangesAsync();
    await transaction.CommitAsync();
}
catch
{
    await transaction.RollbackAsync();
    throw;
}

内容的提问来源于stack exchange,提问作者Addison K. Samuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:37:26