事务范围(TransactionScope)总是试图升级为MSDTC。

7
我正在尝试在循环内使用事务范围。整个循环过程中只使用一个数据库连接。我正在使用Entity Framework 4进行数据库访问。在循环的第二次迭代期间,当执行LINQ to Entites查询时,会抛出一个异常,指出服务器上的MSDTC不可用。
我已经阅读了明确打开连接然后注册事务应该解决此问题的内容,但并没有成功。下面是示例代码,反映了正在进行的基本操作。
有什么想法可以防止升级到MSDTC?
Using context = New MyEntities()
    Dim connection = context.Connection

    connection.Open()

    For index = 0 to (Me.files.Count - 1)
        Dim query = From d In context.Documents
                    Where (d.DocumentID = documentID)
                    Select d.Status

        Dim status = query.FirstOrDefault()

        Using trans = New TransactionScope()
            connection.EnlistTransaction(Transaction.Current)

            Dim result = context.UpdateStatus(True)

            If (result = 1) Then
                WriteToFile()
                trans.Complete()
            End If
        End Using
    Next
End Using

编辑:如果我使用connection.BeginTransaction()、transaction.Commit()和transaction.Rollback(),而不是TransactionScope,它可以正常工作。然而,我仍然希望找到一种使TransactionScope正常工作的方法。


这篇论坛帖子有帮助吗?http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/c3fd7555-7fff-44b8-8e1e-030073c20597/ 看起来建议是先开始事务,然后打开连接,最后运行查询。 - mkedobbs
这个想法是打开连接,然后使用一个连接运行所有查询 - 出于性能考虑。 - DCNYAM
如果使用连接池,这并不会影响性能。 - Ladislav Mrnka
2个回答

1

TransactionScope 最初存在一个问题,即当它遇到另一个连接时,即使所有连接都是到同一个数据库,它也会将事务升级为分布式事务。这是框架中已知的问题。

我相信他们在 .NET 4 中解决了这个问题,你使用的是哪个版本?

在此答案中提供了一种解决方法:

为什么 TransactionScope 在我只使用 LinqToSql 和 Ado.Net 时使用分布式事务

基本上与您的问题的评论建议实际上只使用池中的一个物理连接-因此只有一个连接被注册相同。

再次审查您的问题,我可以看到上述方法不太可能产生影响,因为您只使用一个连接。也许尝试在每次迭代时显式关闭和重新打开连接,并利用连接池的好处。

或者更理想的是,放弃使用 TransactionScope,因为 IDbTransaction 在这里具有足够的范围来覆盖您的代码。


一旦您使用多个连接,事务必须升级为分布式事务——无论它们是否连接到同一个数据库。当没有涉及其他事务资源时,本地事务仅在单个连接上处理。 - Ladislav Mrnka
这个论坛问题的答案表明这是一个限制,并将得到解决:http://social.msdn.microsoft.com/forums/en-US/adodotnetdataproviders/thread/3ce488eb-55a8-4535-adc7-c5b29a1523b5/ - Adam Houldsworth
然而,它们并不完全是与 OP 相同的情况。我似乎正在比较的情况是当一个事务范围具有多个连接时,而 OP 似乎只有一个连接和多个事务范围...以前没有见过这种情况。 - Adam Houldsworth
正如Adam建议的那样,我最终在每个TransactionScope内部使用了一个新的连接对象。在测试过程中,这似乎没有任何性能问题,并且消除了MSDTC问题。 - DCNYAM

1
你有看过MSDNEnlistTransaction的说明吗?它说:

ADO.NET 2.0中新增了对使用EnlistTransaction方法加入分布式事务的支持。因为它将连接注册到一个Transaction实例中,所以EnlistTransaction利用了System.Transactions命名空间中可用于管理分布式事务的功能。一旦一个连接显式地注册到一个事务中,就不能取消注册或者再注册到另一个事务中,直到第一个事务结束。

它只提到了分布式事务。你可以尝试使用connection.BeginTransaction代替它。这将返回一个EntityTransaction实例,你可以调用Commit来完成事务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接