1

ADO.Net を介した1つの接続で複数の呼び出しを使用して、ストアドプロシージャを非同期に呼び出そうとしていますSqlCommand

呼び出しはタイマーで 0.5 秒ごとにトリガーされ、しばらくの間、期待どおりに結果が返され、次のエラーが表示されることがあります。

System.Data.SqlClient.SqlException (0x80131904): 現在のコマンドで重大なエラーが発生しました。結果がある場合は、破棄する必要があります。
System.Data.SqlClient.SqlConnection.OnError (SqlException 例外、ブールn breakConnection)
で System.Data.SqlClient.SqlInternalConnection.OnError (SqlException 例外、ブール型 breakConnection)
で System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() で System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
で。 Data.SqlClient.TdsParser.Run(RunBehavior runBehavior、SqlCommand cm dHandler、SqlDataReader dataStream、BulkCopySimpleResultSet bulkCopyHandler、Tds ParserStateObject stateObj)
System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
で System.Data.SqlClient.SqlDataReader.get_MetaData()
System.Data.SqlClient.SqlCommand.FinishExecuteReader (SqlDataReader ds、実行動作 runBehavior、文字列 resetOptionsString)
で System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
で System.Data.SqlClient.SqlCommand.InternalEndExecuteReader (IAsyncResult asy ncResult、文字列 endMethod) )
System.Data.SqlClient.SqlCommand.EndExecuteReader (IAsyncResult asyncResult) で

SQL ログに次のエラーが繰り返し表示されます。

セッションがシングル ユーザー モードのときにクライアント ドライバーが複数の要求を送信したため、サーバーは接続を切断します。このエラーは、セッションでバッチがまだ実行されている間にクライアントが接続をリセットする要求を送信した場合、またはセッションが接続をリセットしている間にクライアントが要求を送信した場合に発生します。クライアント ドライバーのベンダーに問い合わせてください。

接続文字列に MARS と Async=true が設定されています。現在、SQL Server 2008 Express を使用していますが、ターゲット クライアントは本格的な SQL Server インスタンスになります。

私のマシンで同じ動作を示す次のコンソールアプリを作成しました。作成したものはDummySp、呼び出されるとすぐに戻ります

public class BusinessObject
{
    public string  Name {get; set;}
    public void UpdateData(DataTable dataTable)
    {
        Console.WriteLine("{0}: new data received.",Name);
    }
}

public class Program
{
    private const string SpName = "DummySp";
    private const string ConnectionsString = @"Data Source=(local)\sqlexpress;Initial Catalog=Test;Integrated Security=SSPI;Connection Timeout=3600";

    private static readonly object DbRequestLock = new object();
    private static readonly ManualResetEvent DatabaseRequestsComplete = new ManualResetEvent(false);
    private static int _databaseRequestsLeft;
    private static Timer _timer;

    static readonly List<BusinessObject> BusinessObjects = new List<BusinessObject>
    {
        new BusinessObject{Name = "A"},
        new BusinessObject{Name = "B"},
        new BusinessObject{Name = "C"},
    };

    static void Main(string[] args)
    {
        _timer = new Timer(DoQuery, null, 0, 500);

        Console.ReadLine();

        _timer.Dispose();         
    }

    private static void DoQuery(object state)
    {
        try
        {
           lock (DbRequestLock)
            {

                DatabaseRequestsComplete.Reset();
                _databaseRequestsLeft = BusinessObjects.Count;

                var builder = new SqlConnectionStringBuilder(ConnectionsString)
                    {
                        AsynchronousProcessing = true,
                        MultipleActiveResultSets = true
                    };

                using (var connection = new SqlConnection(builder.ConnectionString))
                {
                    connection.Open();

                    foreach (var businessObject in BusinessObjects)
                    {
                        var command = new SqlCommand(SpName, connection) { CommandType = CommandType.StoredProcedure };

                        command.BeginExecuteReader(Callback, new Tuple<SqlCommand, BusinessObject>(command, businessObject));
                    }

                    // need to wait for all to complete before closing the connection
                    DatabaseRequestsComplete.WaitOne(10000);
                    connection.Close();
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Following error occurred while attempting to update objects: " + ex);
        }
    }

    private static void Callback(IAsyncResult result)
    {
        try
        {
            var tuple = (Tuple<SqlCommand, BusinessObject>)result.AsyncState;
            var businessObject = tuple.Item2;

            using (SqlCommand command = tuple.Item1)
            {
                using (SqlDataReader reader = command.EndExecuteReader(result))
                {
                    using (var table = new DataTable(businessObject.Name))
                    {
                        table.Load(reader);

                        businessObject.UpdateData(table);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        finally
        {
            // decrement the number of database requests remaining and, if there are 0 fire the mre
            if (Interlocked.Decrement(ref _databaseRequestsLeft) == 0)
            {
                DatabaseRequestsComplete.Set();
            }
        }
    }
}

これを克服する方法についてのアイデアはありますか?

ありがとう

4

1 に答える 1

1

これは私の質問に直接答えているわけではないので、そのようにマークしていませんが、問題を回避しているように見えるため、オブジェクトごとに単一の接続を持つという代替案を示す価値があると思いました...

 private static void DoQuery(object state)
    {
        try
        {
            lock (DbRequestLock)
            {

                var builder = new SqlConnectionStringBuilder(ConnectionsString)
                    {
                        AsynchronousProcessing = true,
                    };

                DatabaseRequestsComplete.Reset();
                _databaseRequestsLeft = BusinessObjects.Count;

                foreach (var businessObject in BusinessObjects)
                {
                    var newConnection = new SqlConnection(builder.ConnectionString);
                    newConnection.Open();

                    var command = new SqlCommand(SpName, newConnection) { CommandType = CommandType.StoredProcedure };

                    command.BeginExecuteReader(Callback, new Tuple<SqlCommand, BusinessObject>(command, businessObject),CommandBehavior.CloseConnection);

                }
                // need to wait for all to complete                    DatabaseRequestsComplete.WaitOne(10000);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Following error occurred while attempting to update objects: " + ex);
        }
    }

    private static void Callback(IAsyncResult result)
    {
        var tuple = (Tuple<SqlCommand, BusinessObject>)result.AsyncState;
        var businessObject = tuple.Item2;
        SqlCommand command = tuple.Item1;
        try
        {
            using (SqlDataReader reader = command.EndExecuteReader(result))
            {
                using (var table = new DataTable(businessObject.Name))
                {
                    table.Load(reader);

                    businessObject.UpdateData(table);
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        finally
        {
            // decrement the number of database requests remaining and, if there are 0 fire the mre
            if (Interlocked.Decrement(ref _databaseRequestsLeft) == 0)
            {
                DatabaseRequestsComplete.Set();
            }

            try
            {
                command.Dispose();
                command.Connection.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
于 2013-10-30T09:11:20.767 に答える