在我的代码中有要处理的事务:

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/

    10-13 03:15