在TransactionScope中的DbContext.SaveChanges()可见性 [英] DbContext.SaveChanges() visibility within a TransactionScope

查看:183
本文介绍了在TransactionScope中的DbContext.SaveChanges()可见性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Given a TransactionScope with 2 subsequently opened DbContexts, are changes saved by the first context guaranteed to be visible within the scope of second 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();
}

通常我希望它们是,但是随后我看到了 不,这是一个巧合,因为第二个上下文重用了连接池中第一个的连接。这不能保证,并且会在负载下中断。使我感到困惑。有人可以确认还是反对?

Normally I would expect they are, but then I saw "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." which made me puzzled. Could anyone please confirm or disprove this?

推荐答案

我的理解将竭尽全力,以确保您的线程从池中接收到相同的连接,前提是您在请求每个连接之前先关闭了每个连接,并且连接字符串相同。重用相同的连接将防止事务升级为DTC。

My understanding is that all efforts will be made to ensure that your thread receives the same connection from the pool, provided that you close each connection prior to requesting another, and provided that the connection strings are identical. Reusing the same connection will prevent the transaction from escalating to DTC.

但是,如果您仍然需要进一步的保证,则可以使用采用现有连接的DbContext 构造函数的重载。这样,您将能够保证两个上下文使用相同的连接。这样,您无需担心轻量级事务管理器的行为。 IMO最好是将自己的连接打开,并将其传递到两个上下文,并把 contextOwnsConnection 标志设置为false。

However if you still want further guarantees, there is an overload of the DbContext constructor which takes an existing connection. In this way, you would be able to guarantee that the two Contexts use the same Connection. This way you don't need to worry about the behaviour of the lightweight transaction manager. IMO you'd be best off opening your own connection, and passing this to both contexts, with the contextOwnsConnection flag set to false.

(希望下面的内容都是假设的)

不重用连接的后果非常严重-如果 context2 不能能够重用与 context1 相同的连接,即边界 TransactionScope 将升级为分布式事务,无论如何将导致进一步的潜在锁定和死锁问题。

The consequences of not reusing the connection are dire - if context2 was not able to reuse the same connection as context1, the bounding TransactionScope would escalate into a distributed transaction, which would in any case cause further potential lock + deadlock issues.

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

i.e. in your example, the 3 rows associated with the modified employees in context1 would be blocked to a second database connection on context2 with a ReadCommited isolation level, until the Transaction is either committed, or rolled back (i.e. your program could hang until the transaction, or command, timed out).

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

I guess one burning question - since both contexts use the same database, if possible, try to combine the two contexts. This way you can avoid the bounding TransactionScope altogether - SaveChanges() acts as a single phase transaction against a single connection.

这篇关于在TransactionScope中的DbContext.SaveChanges()可见性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆