1

当我调用我的存储库 10000 次时,它要么需要几分钟(对于一个非常简单的键控查询,在数据库本身上不需要几分钟),要么会因为连接池耗尽消息而迅速死亡。我知道我在处理对象、创建对象、DI 容器寿命等的某些组合上做错了。我究竟做错了什么?我尝试了 .Singleton / .Scoped 的一些排列,数据库的 ThreadLocal 缓存等。

代码在 Windows 10 上执行,框架是 .NET Standard 2.1(在 .NET Core 3.1 上运行),与 SQL Server 2016 通信。

我的注册政策(Lamar):

    public NPocoRegistry()
    {
        For<IDatabase>()
            .Use(ctx => ctx.GetInstance<DatabaseFactory>().GetDatabase())
            .Scoped();

        For<DatabaseFactory>().Use(ctx =>
        {
            var configuration = ctx.GetInstance<IConfiguration>();

            Database CreateDatabase()
            {
                return new Database(configuration.GetConnectionString("EdgeDev"),
                    DatabaseType.SqlServer2012,
                    SqlClientFactory.Instance)
                {
                    KeepConnectionAlive = true
                };
            }

            var configs = FluentMappingConfiguration.Configure(ctx.GetAllInstances<IMap>().ToArray());

            return DatabaseFactory.Config(cfg => cfg
                .UsingDatabase(CreateDatabase)
                .WithFluentConfig(configs)
                .WithMapper(new BooleanMapper())
                .WithMapper(new BinaryStringMapper()));
        }).Singleton();

        Scan(scan =>
        {
            scan.TheCallingAssembly();
            scan.AddAllTypesOf<IMap>();
        });
    }

我的基础存储库:

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);
    }
}

使用此模式的示例存储库:

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);
    }
}

它实际上是如何被调用的:

    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");
    }
4

0 回答 0