C#在TransactionScope事务中获取当前连接

3

我希望在一个.NET 2.0项目中,使用一系列的sp call(SQL Server 2005)使一些业务逻辑变得事务性。

using(TransactionScope...)

很不幸,我从另一个项目继承了DAL,我不想在那里做太多更改...问题是每个调用存储过程的方法都会打开一个新连接。所以,我的问题是:有没有一种方法可以检索当前事务使用的连接,即从Transaction.Current?谢谢。
更新:请告诉我这个控制台应用程序有什么问题(vs2005,.net 2.0,Sql server 2005)
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Transactions;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
            {
                Console.WriteLine("1");
                test();
                Console.WriteLine("2");
                test();
            }
            Console.WriteLine("END");
        }

        public static void test()
        {
            string connectionString = @"Persist Security Info=True;User ID=usr123;Password=123;Initial Catalog=db123;Data Source=myserver\myinstance;Connect Timeout=180;";

            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();
            }
        }
    }
}

如果您在TransactionScope范围内,只需创建自己的连接即可(我相信会自动)将其注册到该范围中。这是您想要避免的吗? - Matt Mills
是的,DAL 中的每个方法都会实例化一个新的 SqlConnection("querystring.."),打开它,然后在 SqlCommand 中使用它。可能的问题是每个方法也在 Dispose() 或 Close() 它! - socste2
所以你想获取TransactionScope本身正在使用与数据库通信的连接? - Matt Mills
没错,我必须编写一些连接持有器的代码,就像微软企业库数据访问应用程序块中的那个一样。 - socste2
3个回答

1

好的,有几件事情:

  1. 我怀疑TransactionScope甚至没有(Sql)Connection的概念。原因是它可以处理各种事务资源,无论是数据库、消息队列系统还是其他什么东西。你可以参考MSDN文档System.Transactions获取更多信息。所以,我想你的方法从一开始就注定要失败。

  2. 在你的示例中,你没有在上面调用"ts.Complete()",因此当using-Scope结束时,你的(分布式)事务将始终被回滚。现在,这与你描述的问题无关,但还是值得指出的。

  3. 你的环境事务,由TransactionScope实例所表示,会传播到分布式事务中,因为你在其中使用了多个连接。因此,实质上,你的系统上的DTC需要与数据库服务器上的DTC进行通信。为了使其工作,两者都必须正确配置。

配置DTC,请执行“组件服务”管理控制台,运行C:\Windows\System32\com\comexp.msc。在树形视图中导航到“组件服务\计算机\我的电脑”。在上下文菜单中打开“属性”。在属性对话框中选择“MSDTC”选项卡,在其中单击“安全配置...”按钮。

在对话框中,请确保选择以下选项:

  • “网络DTC访问”
  • “允许远程客户端”
  • “允许入站”
  • “允许出站”
  • “启用事务Internet协议(TIP)事务”
  • “启用XA事务”

(注意:这些选项可能并非全部必要,因人而异)

根据您的本地政策/要求,您还可以将其设置为“不需要身份验证”。

您需要在两个系统上都进行此操作:一个是您的应用程序运行的系统,另一个是数据库所在的系统。


好的,无论如何感谢您。我会进行一些重构,以跟踪TransactionScope内部的单个SqlConnection。 - socste2

1

好的,谢谢大家。最终我写了类似于Enterprise Library中Microsoft.Practices.EnterpriseLibrary.Data.TransactionScopeConnections的东西(http://entlib.codeplex.com)。


0

除非出于某种原因您不使用连接池,否则没有理由不直接新建一个SqlConnection并开始工作。让运行时处理使其高效的细节 - 这就是连接池的作用。听起来DAL编写正确:

...
using (var conn = new SqlConnection("connection string"))
{
    using (var cmd = conn.CreateCommand())
    {
        conn.Open();
        //Do stuff with cmd
    }
}
....

即使您不使用连接池(并且有充分的理由不这样做),最好的方法仍然是新建一个SqlConnection并开始操作。您不希望意外地关闭事务范围正在使用的连接,而且这还假定它实际上有一个SqlConnection供您引用。

好的,我编辑了问题并附上了用于测试的代码。当它尝试第二次调用conn.Open()时,我会得到异常信息“已禁用Distributed Transaction Manager (MSDTC)的网络访问...” - socste2
你是连接到远程数据库服务器还是本地机器上的实例? - Matt Mills
你需要经过DTC设置过程,以确保DTC能够管理从你的Web服务器到SQL服务器之间的事务。这其中涉及一些操作系统的设置,可能还需要防火墙的设置,但是在谷歌上有很多好的信息可供参考。 - Matt Mills
今天早上我尝试了使用.NET 3.5和SQL Server 2008相同的代码,行为与我最初预期的一样:两个单独的连接在同一个事务中注册,而不会升级为分布式事务。我认为TransactionScope问题的最完整的答案是这个:https://dev59.com/qXE85IYBdhLWcg3wNwx3。 - socste2
如果你告诉我SQL Server 2008实例也在应用程序运行的不同机器上,我会感到惊讶但不会震惊。这是真的吗? - Matt Mills
显示剩余3条评论

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