代码之家  ›  专栏  ›  技术社区  ›  Vladi Pavelka

transactionScope中的dbContext.saveChanges()可见性

  •  1
  • Vladi Pavelka  · 技术社区  · 8 年前

    给定一个transactionscope包含两个随后打开的dbcontext,第一个context保存的更改是否保证在第二个context的范围内可见?

    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. “这让我很困惑。有人能证实或反驳这一点吗?

    1 回复  |  直到 8 年前
        1
  •  1
  •   StuartLC    8 年前

    My understanding 那是 all efforts 将确保您的线程从池接收到相同的连接,前提是您在请求另一个连接之前关闭了每个连接,并且连接字符串相同。重用同一个连接将防止事务升级到dtc。

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

    (希望下面都是假设的)

    不重用连接的后果是可怕的-if context2 能够重复使用与 context1 ,边界 TransactionScope 会升级为分布式事务,这在任何情况下都会导致进一步的潜在锁+死锁问题。

    例如,在您的示例中,与 上下文1 将被阻止到上的第二个数据库连接 上下文二 用一个 ReadCommited 隔离级别,直到事务提交或回滚(即,您的程序可以挂起,直到事务或命令超时)。

    我想有一个紧迫的问题-因为两个上下文都使用同一个数据库,如果可能的话,试着将这两个上下文结合起来。这样你就可以避免 交易范围 完全- SaveChanges() 作为针对单个连接的单阶段事务。