交易期间的MSDTC异常:C#

时间:2011-06-19 10:49:50

标签: c# sql-server-2005 exception transactions msdtc

我在C#应用程序的事务中收到MSDTC异常。该功能是在从csv文件读取后将一万(十万)个zipcode记录上传到数据库表中。此操作在大约20个批处理数据库操作中完成(每个批处理包含5000个记录)。如果我不使用事务,则功能正常。

有趣的是,使用交易的其他功能可以完成交易。这使我假设异常消息具有误导性。

关于可能出现什么问题的任何想法?

例外:“已禁用分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问。“

来源:System.Transactions

内部异常:“事务管理器已禁用其对远程/网络事务的支持。 (HRESULT异常:0x8004D024)“

注意:事务中有一个for循环。这会引起任何问题吗?

实际要求是:zipcode表中有一些现有的zipcodes。管理员每个月都会上传新的zipcode csv文件。来自csv的新项目已插入。 csv中不可用的邮政编码(但存在于数据库中)被视为已停用且将被删除。退役邮政编码列表将返回到用户界面。新添加的邮政编码也需要退回。

    private void ProcessZipCodes(StringBuilder dataStringToProcess, int UserID)
    {
        int CountOfUnchangedZipCode = 0;
        string strRetiredZipCode = "";
        string strNewZipCode = "";
        dataStringToProcess.Remove(dataStringToProcess.Length - 1, 1);

        if (dataStringToProcess.Length > 0)
        {

            List<string> batchDataStringList = GetDataStringInBatches(dataStringToProcess);

           //TimeSpan.FromMinutes(0) - to make transaction scope as infinite.
            using (TransactionScope transaction = TransactionScopeFactory.GetTransactionScope(TimeSpan.FromMinutes(0)))
            {

                foreach (string dataString in batchDataStringList)
                {
                    PerformDatabaseOperation(dataString, UserID);
                }

                transaction.Complete();
            }
        }


    }

    private List<string> GetDataStringInBatches(StringBuilder dataStringToProcess)
    {

        List<string> batchDataStringList = new List<string>();
        int loopCounter = 0;
        string currentBatchString = string.Empty;
        int numberOfRecordsinBacth = 5000;
        int sizeOfTheBatch = 0;

        List<string> individualEntriesList = new List<string>();
        string dataString = string.Empty;
        if (dataStringToProcess != null)
        {
            dataString = dataStringToProcess.ToString();
        }
        individualEntriesList.AddRange(dataString.Split(new char[] { '|' }));


        for (loopCounter = 0; loopCounter < individualEntriesList.Count; loopCounter++)
        {

            if (String.IsNullOrEmpty(currentBatchString))
            {
                currentBatchString = System.Convert.ToString(individualEntriesList[loopCounter]);
            }
            else
            {
                currentBatchString = currentBatchString+"|"+System.Convert.ToString(individualEntriesList[loopCounter]);
            }

            sizeOfTheBatch = sizeOfTheBatch + 1;
            if (sizeOfTheBatch == numberOfRecordsinBacth)
            {
                batchDataStringList.Add(currentBatchString);
                sizeOfTheBatch = 0;
                currentBatchString = String.Empty;
            }


        }

        return batchDataStringList;


    }

    private void PerformDatabaseOperation(string dataStringToProcess, int UserID)
    {
        SqlConnection mySqlConnection = new SqlConnection("data source=myServer;initial catalog=myDB; Integrated Security=SSPI; Connection Timeout=0");
        SqlCommand mySqlCommand = new SqlCommand("aspInsertUSAZipCode", mySqlConnection);
        mySqlCommand.CommandType = CommandType.StoredProcedure;
        mySqlCommand.Parameters.Add("@DataRows", dataStringToProcess.ToString());
        mySqlCommand.Parameters.Add("@currDate", DateTime.Now);
        mySqlCommand.Parameters.Add("@userID", UserID);
        mySqlCommand.Parameters.Add("@CountOfUnchangedZipCode", 1000);
        mySqlCommand.CommandTimeout = 0;
        mySqlConnection.Open();
        int numberOfRows = mySqlCommand.ExecuteNonQuery();
    }

Dev Env:Visual Studion 2005

框架:.Net 3.0

DB:SQL Server 2005

当我运行查询SELECT [Size],Max_Size,Data_Space_Id,[File_Id],Type_Desc,[Name] FROM MyDB.sys.database_files WHERE data_space_id = 0 - 它表示(日志的)大小是128

更新 我们的应用程序中使用了三个不同的数据库。一个用于数据,一个用于历史记录,一个用于记录。当我在上面的连接字符串中放入enlist = false时,它暂时正常工作。但它在我的开发环境中。我怀疑它是否也适用于生产。有关潜在风险的想法吗?

由于

Lijo

3 个答案:

答案 0 :(得分:6)

当您在TransactionScope内打开多个连接时,正在运行的事务将自动升级为分布式事务。要使分布式事务起作用,必须将SQL Server和运行应用程序的计算机上的MSDTC配置为允许网络访问。运行分布式事务时,SQL Server和本地DTC进行通信。

您的情况下的问题很可能是运行您的应用程序的计算机上的MSDTC不允许网络访问,因为这是工作站的默认设置。要解决此问题,请执行以下操作:

  1. 转到“控制面板” - &gt; “行政” - &gt; “组件服务”。
  2. 浏览树,直到找到名为“Local DTC”的节点或类似的节点。
  3. 右键单击并选择“属性”。
  4. 转到“安全”并确保您允许网络访问,并允许与DTC进行入站和出站通信。
  5. 点击“确定”。
  6. 可能会提示您重新启动DTC。 UI中似乎存在错误,因为即使您接受重新启动DTC,也不会重新启动它。相反,您必须在服务管理器中手动重新启动DTC服务。

    顺便说一下,记得在PerformDatabaseOperation中使用后关闭连接。最好将它放在using块中:

    using (SqlConnection mySqlConnection = new .....)
    {
        // Some code here...
        mySqlConnection.Open();
        // Some more code ...
    }
    

答案 1 :(得分:1)

aspInsertUSAZipCode是否可能与链接服务器进行交互?如果是,那么它将尝试将当前本地事务提升为分布式事务(在服务器和链接服务器之间保留事务完整性)。

如果远程服务器上的MSDTC无法配置为分布式事务,则可能需要在事务外部执行此操作。我认为最好的方法是创建一个临时表,然后SqlBulkCopy将记录放入其中,然后使用服务器上的临时表执行aspInsertUSAZipCode。您可能需要使用光标。

临时表的目的是在出现问题时,在连接终止时删除表。

答案 2 :(得分:0)

您可能在交易限制中达到了一些最大数量的数据。

检查事件日志中是否存在任何msdtc错误http://technet.microsoft.com/en-us/library/cc774415(WS.10).aspx

在一次交易中拥有100,000行会给你带来麻烦。

在这种情况下,我不认为单个事务会起作用,您需要查看此处使用事务的原因,并找到完成它的不同方法。