鉴于TransactionScope有2个随后打开的DbContexts,第一个上下文保存的更改是否保证在第二个上下文的范围内可见?
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.”让我感到困惑。有人可以确认或反驳这个吗?
答案 0 :(得分:1)
My understanding是all efforts将确保您的线程从池接收相同的连接,前提是您在请求另一个连接之前关闭每个连接,并且连接字符串是相同的。重复使用相同的连接将阻止事务升级到DTC。
但是,如果您仍需要进一步的保证,则会有overload of the DbContext构造函数接受现有连接。这样,您就可以保证两个上下文使用相同的Connection。这样您就不必担心轻量级事务管理器的行为。 IMO您最好打开自己的连接,并将此传递给两个上下文,并将contextOwnsConnection
标志设置为false。
(希望下面的内容都是假设的)
不重复使用连接的后果非常糟糕 - 如果context2
context1
,那么边界TransactionScope
会升级进入分布式事务,这在任何情况下都会导致进一步的潜在锁定+死锁问题。
即。在您的示例中,与context1
中已修改员工关联的3行将被阻止到context2
上具有ReadCommited
隔离级别的第二个数据库连接,直到提交事务为止,或者回滚(即您的程序可能会挂起,直到事务或命令超时)。
我想一个亟待解决的问题 - 因为两个上下文都使用相同的数据库,如果可能的话,尝试组合这两个上下文。通过这种方式,您可以完全避免绑定TransactionScope
- SaveChanges()
充当针对单个连接的单阶段事务。