使用不带 DTC 的单个环境 TransactionScope 将多个 DbContext 实例连接到同一数据库

问题描述 投票:0回答:0

听起来像互联网上的大多数问题,但事情是这样的——当在单一环境中建立多个连接时

TransactionScope
它将被提升为 DTC。所以问题是,如何避免这种情况并在所有实例之间共享单一连接?有一个连接池机制(至少在
Npgsql
)但我不确定它是否像我预期的那样工作。

这是一个复制品:https://github.com/uhfath/TestTransactionDbContext

该项目包含

Npgsql
Sql Server
的测试方法。他们的行为不同:

  • Sql Server
    我只是得到
    The operation is not valid for the state of the transaction
    .
  • On
    Npgsql
    查询根本不起作用。

项目做的是:

  • 启动环境
    TransactionScope
private static TransactionScope CreateTransaction() =>
    new TransactionScope(
        TransactionScopeOption.Required,
        new TransactionOptions
        {
            IsolationLevel = IsolationLevel.ReadCommitted
        },
        TransactionScopeAsyncFlowOption.Enabled);
  • 创建一个测试客户端:
private static async Task<Client> Create(IServiceProvider serviceProvider)
{
    var client = new Client { Name = "client_1" };

    await using var scope = serviceProvider.CreateAsyncScope();
    var dbContext = scope.ServiceProvider.GetRequiredService<AsyncDbContext>();
    dbContext.Clients.Add(client);
    await dbContext.SaveChangesAsync();

    await Console.Out.WriteLineAsync($"Client: {client.Id}");
    return client;
}
  • 启动 100 个任务来读取这个创建的客户端(使用返回的 Id):
private static Random _randomer = new();
private static async Task Read(IServiceProvider serviceProvider, DependentTransaction dependentTransaction, int clientId, int index)
{
    using (dependentTransaction)
    {
        //using (var transaction = CreateTransaction(dependentTransaction))
        {
            await using (var scope = serviceProvider.CreateAsyncScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<AsyncDbContext>();
                await Task.Delay(_randomer.Next(100, 250));
                var client = await dbContext.Clients.AsNoTracking().Where(cl => cl.Id == clientId).SingleOrDefaultAsync();
                await Console.Out.WriteLineAsync($"Read: {index} -> {client?.Id.ToString() ?? "!! NOT FOUND !!"}");
                //transaction.Complete();
            }
        }

        dependentTransaction.Complete();
    }
}

主要问题是我需要并行读取数据,这只是主要的、更大的项目的一个简单示例,目标是相同的(它只是使用并行执行的插件,每个插件都通过 DI 实例化

DbContext
).

正如我所提到的,当使用

Sql Server
时我得到一个异常,但是当使用
Npgsql
时,查询有时返回正确的结果,有时返回
!! NOT FOUND !!
。后者让人相信在查询运行时事务以某种方式“回滚”。

那么我们实际上如何在所有这些

DbContext
实例之间共享连接,这样事务就不会升级为 DTC?

c# sql-server entity-framework-core transactions npgsql
© www.soinside.com 2019 - 2024. All rights reserved.