.net core .NET Core 3.1上的NPoco耗尽连接池

.net core .NET Core 3.1上的NPoco耗尽连接池,.net-core,sqlclient,npoco,.net Core,Sqlclient,Npoco,当我调用我的存储库10000次时,它要么需要几分钟(对于一个非常简单的键控查询,对数据库本身进行查询不需要几分钟),要么随着连接池耗尽消息而很快消失。我知道我在处理对象、创建对象、DI容器的使用寿命等方面做了一些错误的组合。我做错了什么?我尝试了一些.Singleton/.Scoped的排列,数据库的ThreadLocal缓存,等等 代码在Windows 10上执行,框架为.NET标准2.1(运行在.NET Core 3.1上),与SQL Server 2016对话 我的注册政策(Lamar):

当我调用我的存储库10000次时,它要么需要几分钟(对于一个非常简单的键控查询,对数据库本身进行查询不需要几分钟),要么随着连接池耗尽消息而很快消失。我知道我在处理对象、创建对象、DI容器的使用寿命等方面做了一些错误的组合。我做错了什么?我尝试了一些.Singleton/.Scoped的排列,数据库的ThreadLocal缓存,等等

代码在Windows 10上执行,框架为.NET标准2.1(运行在.NET Core 3.1上),与SQL Server 2016对话

我的注册政策(Lamar):

public NPocoRegistry()
{
For()
.Use(ctx=>ctx.GetInstance().GetDatabase())
.Scoped();
For()。使用(ctx=>
{
var configuration=ctx.GetInstance();
数据库CreateDatabase()
{
返回新数据库(configuration.GetConnectionString(“EdgeDev”),
DatabaseType.SqlServer2012,
SqlClientFactory.Instance)
{
KeepConnectionAlive=true
};
}
var configs=FluentMappingConfiguration.Configure(ctx.GetAllInstances().ToArray());
返回DatabaseFactory.Config(cfg=>cfg
.UsingDatabase(CreateDatabase)
.WithFluentConfig(配置)
.WithMapper(新布尔映射器())
.WithMapper(新的BinaryStringMapper());
}).Singleton();
扫描(扫描=>
{
扫描。卡入总成();
scan.AddAllTypesOf();
});
}
我的基本存储库:

public abstract class BaseNPocoRepository<T>
{
    private readonly DatabaseFactory _dbFactory;
    private readonly ThreadLocal<IDatabase> _databaseLocal;

    protected BaseNPocoRepository(DatabaseFactory dbFactory)
    {
        _dbFactory = dbFactory;
        _databaseLocal = new ThreadLocal<IDatabase>(_dbFactory.GetDatabase);
    }

    protected virtual IDatabase GetDatabase() => _databaseLocal.Value;

    public virtual async Task CreateAsync(T item)
    {
        using var database = GetDatabase();
        await database
            .InsertAsync(item)
            .ConfigureAwait(false);
    }

    public virtual async Task UpdateAsync(T item)
    {
        using var database = GetDatabase();
        await database
            .UpdateAsync(item)
            .ConfigureAwait(false);
    }

    public virtual async Task DeleteAsync(T item)
    {
        using var database = GetDatabase();
        await database
            .DeleteAsync(item)
            .ConfigureAwait(false);
    }

    public virtual async Task<IEnumerable<T>> RetrieveManyAsync()
    {
        using var database = GetDatabase();
        return await database
            .Query<T>()
            .ToEnumerableAsync()
            .ConfigureAwait(false);
    }
}
公共抽象类BaseNPocoRepository
{
私有只读数据库工厂(dbFactory);
私有只读ThreadLocal_databaseLocal;
受保护的BaseNPocoRepository(DatabaseFactory dbFactory)
{
_dbFactory=dbFactory;
_databaseLocal=newthreadlocal(_dbFactory.GetDatabase);
}
受保护的虚拟IDatabase GetDatabase()=>\u databaseLocal.Value;
公共虚拟异步任务CreateAsync(T项)
{
使用var database=GetDatabase();
等待数据库
.InsertAsync(项目)
.配置等待(错误);
}
公共虚拟异步任务UpdateAsync(T项)
{
使用var database=GetDatabase();
等待数据库
.UpdateSync(项目)
.配置等待(错误);
}
公共虚拟异步任务DeleteAsync(T项)
{
使用var database=GetDatabase();
等待数据库
.DeleteAsync(项目)
.配置等待(错误);
}
公共虚拟异步任务RetrieveManyAsync()
{
使用var database=GetDatabase();
返回等待数据库
.Query()
.ToEnumerableAsync()
.配置等待(错误);
}
}
使用此模式的示例存储库:

public class T_AccountRepository : BaseNPocoRepository<T_Account>
    , IRetrieveMany<T_Account>
    , IRetrieve<AccountId, T_Account>
{
    public T_AccountRepository(DatabaseFactory dbFactory) : base(dbFactory)
    {
    }

    public async Task<T_Account> RetrieveAsync(AccountId input)
    {
        using var database = GetDatabase();
        return await database.Query<T_Account>()
            .SingleAsync(x => x.AccountId == (int) input)
            .ConfigureAwait(false);
    }
}
公共类T_AccountRepository:BaseNPocoRepository
,我尝试了很多
,我尝试
{
公共T_AccountRepository(DatabaseFactory dbFactory):基础(dbFactory)
{
}
公共异步任务检索同步(AccountId输入)
{
使用var database=GetDatabase();
return wait database.Query()
.SingleAsync(x=>x.AccountId==(int)输入)
.配置等待(错误);
}
}
它的实际名称:

    static async Task Main(string[] args)
    {
        Console.WriteLine("Booting up . . .");

        var container = new Container(cfg =>
        {
            cfg.Scan(scan =>
            {
                scan.AssembliesFromApplicationBaseDirectory();
                scan.AssemblyContainingType<NPocoRegistry>();
                scan.LookForRegistries();
                scan.With(new AllInterfacesConvention());
            });
        });

        Console.WriteLine("Getting repository . . . ");
        var repo = container.GetInstance<AccountRepository>();


        Console.WriteLine("Starting benchmark . . .");
        var sw = Stopwatch.StartNew();

        for (int i = 0; i < 10000; i++)
        {
            await repo.RetrieveAsync(1253832471);
        }
        
        Console.WriteLine(sw.ElapsedMilliseconds + "ms");
    }
static async Task Main(字符串[]args)
{
控制台.WriteLine(“启动…”);
var容器=新容器(cfg=>
{
扫描(扫描=>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.AssemblyContainingType();
scan.LookForRegistries();
使用(新的AllInterfacesConvention())扫描;
});
});
控制台.WriteLine(“获取存储库…”);
var repo=container.GetInstance();
WriteLine(“起始基准…”);
var sw=Stopwatch.StartNew();
对于(int i=0;i<10000;i++)
{
等待回购检索同步(1253832471);
}
控制台写入线(sw.ElapsedMilliseconds+“ms”);
}

我认为DI无事可做,在我看来很好,并且只用于解析帐户存储库一次。我认为DI无事可做,在我看来很好,并且只用于解析帐户存储库一次。
    static async Task Main(string[] args)
    {
        Console.WriteLine("Booting up . . .");

        var container = new Container(cfg =>
        {
            cfg.Scan(scan =>
            {
                scan.AssembliesFromApplicationBaseDirectory();
                scan.AssemblyContainingType<NPocoRegistry>();
                scan.LookForRegistries();
                scan.With(new AllInterfacesConvention());
            });
        });

        Console.WriteLine("Getting repository . . . ");
        var repo = container.GetInstance<AccountRepository>();


        Console.WriteLine("Starting benchmark . . .");
        var sw = Stopwatch.StartNew();

        for (int i = 0; i < 10000; i++)
        {
            await repo.RetrieveAsync(1253832471);
        }
        
        Console.WriteLine(sw.ElapsedMilliseconds + "ms");
    }