このような振る舞いは起こらないはずだと思います。シナリオは次のとおりです。
長時間実行されるSQLトランザクションを開始します。
sqlコマンドを実行したスレッドは中止されます(コードではありません!)
スレッドがマネージコードに戻ると、SqlConnectionの状態は「Closed」になりますが、トランザクションはSQLサーバーで開いたままです。
SQLConnectionを再度開くことができ、トランザクションでロールバックを呼び出そうとすることはできますが、効果はありません(この動作を期待するわけではありません。要点は、データベース上のトランザクションにアクセスしてロールする方法がないということです。戻る。)
問題は、スレッドが異常終了したときにトランザクションが適切にクリーンアップされないことです。これは、.Net 1.1、2.0、および2.0SP1の問題でした。.Net3.5SP1を実行しています。
これは、問題を説明するサンプルプログラムです。
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=<YourServer>;Initial Catalog=<YourDB>;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 <YourTable> 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...");
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[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();
}
}
}
}
これに対処するはずの.Net2.0SP1を対象としたMicrosoftHotfixがありますが、この修正プログラムに記載されているバージョン番号と一致しない新しいDLL(.Net 3.5 SP1)があることは明らかです。
誰かがこの動作を説明できますか、そしてなぜThreadAbortがまだSQLトランザクションを適切にクリーンアップしていないのですか?.Net 3.5 SP1にはこの修正プログラムが含まれていませんか、それともこの動作は技術的に正しいですか?