【问题标题】:DbContext.SaveChanges() visibility within a TransactionScopeTransactionScope 中的 DbContext.SaveChanges() 可见性
【发布时间】:2018-06-14 10:36:55
【问题描述】:

给定一个带有 2 个随后打开的 DbContext 的 TransactionScope,第一个上下文保存的更改是否保证在第二个上下文的范围内可见?

var txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
using (var transaction = new TransactionScope(TransactionScopeOption.Required, txOptions))
{
    using (var context1 = new MyDbContext())
    {
        context1.Employees.Single(e => e.Id == 1).Salary += 1; // Update
        context1.Employees.Remove(context1.Employees.Single(e => e.Id == 2)); // Delete
        context1.Employees.Add(new Employee { Id = 3 }); // Add

        context1.SaveChanges();
    }

    using (var context2 = new MyDbContext())
    {
        // are changes saved by context1 guaranteed to be visible here?
    }

    transaction.Complete();
}

通常我会希望他们是,但后来我看到“No, this was a coincidence because the 2nd context reused the connection of the 1st from the connection pool. This is not guaranteed and will break under load.”让我感到困惑。任何人都可以确认或反驳这一点吗?

【问题讨论】:

    标签: c# entity-framework dbcontext transactionscope


    【解决方案1】:

    My understandingall efforts 将确保您的线程从池中接收相同的连接,前提是您在请求另一个连接之前关闭每个连接,并且连接字符串相同。重复使用相同的连接将阻止事务升级到 DTC。

    但是,如果您仍需要进一步的保证,可以使用 overload of the DbContext 构造函数来获取现有连接。这样,您将能够保证两个上下文使用相同的连接。这样您就不必担心轻量级事务管理器的行为。 IMO,您最好打开自己的连接,并将其传递给两个上下文,并将 contextOwnsConnection 标志设置为 false。

    (希望以下都是假设)

    不重用连接的后果是可怕的 - 如果context2 能够重用与context1 相同的连接,则边界TransactionScope 将升级为分布式事务,这无论如何都会导致进一步的潜在锁定+死锁问题。

    即在您的示例中,与 context1 中修改后的员工相关联的 3 行将被阻止到具有 ReadCommited 隔离级别的 context2 上的第二个数据库连接,直到事务被提交或回滚(即您的程序可能会挂起,直到事务或命令超时)。

    我猜有一个亟待解决的问题——因为两个上下文都使用同一个数据库,如果可能的话,尝试将这两个上下文结合起来。这样您就可以完全避免边界 TransactionScope - SaveChanges() 充当针对单个连接的单阶段事务。

    【讨论】:

    • 感谢您的回答斯图尔特! : ) 我正在尝试对我当前工作中的现有代码进行推理,其中 TxScope + 多个 dbContexts 的这种方法被广泛使用。如果它有可能在生产后期出现故障,则需要对其进行修复/重构。当然,如果是我做决定,我会选择一个 DbContext - 它本身已经是一个业务交易。
    • 我已经有一段时间没有做这个了,但我认为“所有的努力都在努力”意味着它会在 99% 的时间里工作,除了在负载下的生产环境,然后可能会导致你的应用程序崩溃。在测试期间,它可以 100% 在您的机器上运行。
    猜你喜欢
    • 2013-06-12
    • 1970-01-01
    • 2010-09-27
    • 2016-10-13
    • 2012-09-24
    • 2012-05-10
    • 1970-01-01
    • 2020-02-10
    • 2013-06-14
    相关资源
    最近更新 更多