SQLException on ADO.Net SqlCommand.EndExecuteReader

本文关键字:SqlCommand EndExecuteReader Net ADO on SQLException | 更新日期: 2023-09-27 18:37:22

我正在尝试异步调用存储过程,通过 ADO.Net SqlCommand在一个连接上进行多次调用。

调用每半秒在计时器上触发一次,在某些时候我按预期收到结果,有时我会收到以下错误:

System.Data.SqlClient.SqlException (0x80131904): 在 当前命令。 结果(如果有的话)应丢弃。
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolea n 中断连接)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception 、布尔中断连接)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cm dHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, Tds ParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
在 System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, Run 行为运行行为,字符串重置选项字符串)
at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
at System.Data.SqlClient.SqlCommand.InternalEndExecuteReader(IAsyncResult asy ncResult, String endMethod)
at System.Data.SqlClient.SqlCommand.EndExecuteReader(IAsyncResult asyncResult )

SQL 日志反复显示以下错误:

服务器将断开连接,因为客户端驱动程序在会话处于单用户模式时发送了多个请求。当客户端在会话中仍有批处理运行时发送重置连接的请求时,或者当客户端在会话重置连接时发送请求时,会发生此错误。请与客户端驱动程序供应商联系。

我的连接字符串设置了 MARS 和异步 = 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();
            }
        }
    }
}

关于如何克服这个问题的任何想法?

谢谢

SQLException on ADO.Net SqlCommand.EndExecuteReader

这并没有直接回答我的问题,所以我没有这样标记它,但我认为值得展示每个对象有一个连接的替代方案,因为这似乎规避了这个问题......

 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);
            }
        }
    }