Прерывание потока оставляет транзакции зомби и прерывает SqlConnection

Я чувствую, что такого поведения не должно быть. Вот сценарий:

  1. Запуск длительной транзакции sql.

  2. Поток, выполнивший команду sql прерывается (не нашим кодом!)

  3. Когда поток возвращается в управляемый код, состояние SqlConnection - «Закрыто» - но сделка все еще открыт на сервере sql.

  4. SQLConnection можно открыть повторно, и вы можете попробовать вызвать откат на сделка, но у нее нет эффект (не то, чтобы я ожидал такого поведения. Дело в том, что нет возможности получить доступ к транзакции в базе данных и откатить ее.)

Проблема просто в том, что транзакция не очищается должным образом при прерывании потока. Это была проблема с .Net 1.1, 2.0 и 2.0 SP1. Мы используем .Net 3.5 SP1.

Вот пример программы, которая иллюстрирует проблему.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Data.SqlClient;
using System.Threading;

namespace ConsoleApplication1
{
    class Run
    {
        static Thread transactionThread;

        public class ConnectionHolder : IDisposable
        {
            public void Dispose()
            {
            }

            public void executeLongTransaction()
            {
                Console.WriteLine("Starting a long running transaction.");
                using (SqlConnection _con = new SqlConnection("Data Source=;Initial Catalog=;Integrated Security=True;Persist Security Info=False;Max Pool Size=200;MultipleActiveResultSets=True;Connect Timeout=30;Application Name=ConsoleApplication1.vshost"))
                {
                    try
                    {
                        SqlTransaction trans = null;
                        trans = _con.BeginTransaction();

                        SqlCommand cmd = new SqlCommand("update  set Name = 'XXX' where ID = @0; waitfor delay '00:00:05'", _con, trans);
                        cmd.Parameters.Add(new SqlParameter("0", 340));
                        cmd.ExecuteNonQuery();

                        cmd.Transaction.Commit();

                        Console.WriteLine("Finished the long running transaction.");
                    }
                    catch (ThreadAbortException tae)
                    {
                        Console.WriteLine("Thread - caught ThreadAbortException in executeLongTransaction - resetting.");
                        Console.WriteLine("Exception message: {0}", tae.Message);
                    }
                }
            }
        }

        static void killTransactionThread()
        {
            Thread.Sleep(2 * 1000);

            // We're not doing this anywhere in our real code.  This is for simulation
            // purposes only!
            transactionThread.Abort();

            Console.WriteLine("Killing the transaction thread...");
        }

        /// 
        /// The main entry point for the application.
        /// 
        [STAThread]
        static void Main(string[] args)
        {
            using (var connectionHolder = new ConnectionHolder())
            {
                transactionThread = new Thread(connectionHolder.executeLongTransaction);
                transactionThread.Start();

                new Thread(killTransactionThread).Start();

                transactionThread.Join();

                Console.WriteLine("The transaction thread has died.  Please run 'select * from sysprocesses where open_tran > 0' now while this window remains open. \n\n");

                Console.Read();
            }
        }
    }
}

Существует исправление Microsoft, предназначенное для .Net2.0 SP1, которое должно было решить эту проблему , но очевидно, что у нас есть более новые библиотеки DLL (.Net 3.5 SP1), которые не соответствуют номерам версий, перечисленным в этом исправлении.

Кто-нибудь может объяснить такое поведение и почему ThreadAbort все еще не очищает sql сделка правильно? Не включает ли .Net 3.5 SP1 это исправление или это технически правильное поведение?

16
задан womp 2 June 2011 в 23:17
поделиться