[英]SQLException on ADO.Net SqlCommand.EndExecuteReader
我正在嘗試通過ADO.Net SqlCommand
在一個連接上與多個調用異步地調用存儲過程。
每隔半秒就會在計時器上觸發一次調用,並且在某些時間段內,我收到的結果與預期的一樣,有時會收到以下錯誤:
System.Data.SqlClient.SqlException(0x80131904):當前命令發生嚴重錯誤。 結果(如果有的話)應丟棄。
在System.Data.SqlClient.SqlConnection.OnError(SqlException異常,Boolea n breakConnection)
在System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception,Boolean breakConnection)
在System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
在System.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,String endMethod)
在System.Data.SqlClient.SqlCommand.EndExecuteReader(IAsyncResult asyncResult)
SQL日志反復顯示以下錯誤:
服務器將斷開連接,因為在會話處於單用戶模式下時,客戶端驅動程序已發送了多個請求。 當客戶端在會話中仍在運行批處理時發出請求重置連接的請求時,或者當客戶端在會話重置連接時發送請求時,將發生此錯誤。 請與客戶端驅動程序供應商聯系。
我的連接字符串具有MARS和Async = true設置。 盡管目標客戶端將是成熟的SQL Server實例,但我目前正在使用SQL Server 2008 Express。
我創建了以下控制台應用程序,該應用程序在我的計算機上表現出相同的行為,我創建的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();
}
}
}
}
關於如何克服這一點的任何想法?
謝謝
這不是直接回答我的問題,因此我沒有將其標記為此類,但是我認為值得展示每個對象具有單個連接的替代方法,因為這似乎可以避免問題的發生...
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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.