在我的代码中有要处理的事务:
using (var scope = new TransactionScope())
{
repo1.SaveSomething();
repo2.SaveAnythingElse();
scope.Complete();
}
在repo1和repo2函数内部,使用事务来创建自己的db上下文,并对其进行处理,就像使它们事务一样。
现在,我添加了另一个这样的代码,它开始删除一个异常:
我读到,尽管在同一个sql server和同一个db中,在事务内部打开连接时-它需要MSDTC组件来处理它。我将代码更改为以下内容:
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted }))
{
....
scope.Complete();
}
现在,异常消失了。
我的问题:
我认为简单的问题:)任何帮助将不胜感激!
最佳答案
1)您绝对应该在TransactionScope的默认Serializable上使用ReadCommitted,但这与您的问题无关,请参阅here。
2)当您有一个事件的TransactionScope时,无论何时打开SqlConnection,它都将在该Transaction中登记。如果没有其他资源参与事务,则SqlClient将开始本地或“轻量级”事务。这不涉及MSTDC;它只是在打开的SqlConnection上启动的普通SQL Server事务。
如果关闭该SqlConnection(或处置包含它的EF DbContext),则该连接将返回到连接池。但是它与其他合并的连接隔离开来,一直挂到事务完成或回滚为止。
如果您在具有完全相同的ConnectionString的相同TransactionScope中打开一个新的SqlConnection,而不是获得一个新的连接,连接池只会将您已经在事务中登记的现有连接返回给您。
如果在相同的TransactionScope中使用不同的ConnectionString打开新的SqlConnection,或者在事务中已征用的连接池中没有连接,则将获得新的SqlConnection并将其征入事务中。但是,由于在事务中已经存在另一个SqlConnection,因此这将要求MSTDC创建一个真正的分布式事务。这就是所谓的“促销”;您的“轻型交易”被“提升”为“分布式交易”。
因此,在此背景下,请审核您的连接生命周期和ConnectionString的使用情况,以了解为什么在此处触发升级。
换句话说,通过正确使用ConnectionString用法和连接生存期管理,您应该能够运行以下代码:
using (var scope = new TransactionScope())
{
repo1.SaveSomething();
repo2.SaveAnythingElse();
scope.Complete();
}
无需触发分布式事务。
关于c# - .NET TransactionScope和MSDTC,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48399623/