经过更多研究,我找到了如何停止 OutOfMemoryException 并采取预期 TimeoutException 的解决方案。
由于存储过程中使用了 PRINT,因此这种情况下的内存正在增长。驱动程序默认从数据库收集输出。因此,如果用户没有阅读此内容,则可能会发生 OutOfMemoryException。
根据您想要的结果,可以使用两种解决方案。
当数据库输出对您不重要并且您期望在执行需要很长时间时出现超时时,第一个很好。下面的片段以这种方式解决了问题:
public void CallProcedure()
{
// Line below release all Errors/PRINT output from command. Command is now
// not collecting them, so memory is not growing.
// CommandTimeout will be thrown after preset value on command object.
this._connection.FireInfoMessageEventOnUserErrors = true;
SqlCommand cmd = this._connection.CreateCommand();
cmd.CommandTimeout = 15;
cmd.CommandType = CommandType.StoredProcedure;
command.CommandText = 'InfiniteLoop';
//Line below throws OutOfMemoryException
cmd.ExecuteNonQuery();
cmd.Dispose();
}
第二个是goog,当您想要执行可能需要大量时间的真正耗时的程序时。永远不会发生超时异常。要启用此行为,您需要在 SqlConnection 中的 InfoMessage 上附加 SqlInfoMessageEventHandler。请参见下面的片段:
public void CallProcedure()
{
// By attaching this event no Timeout exception on ExecuteNonQuery occur
// Your ExecuteNonQuery can hang infinitly!
// If you need Timeout then you need to write you own handler from different thread
this._connection.InfoMessage += new SqlInfoMessageEventHandler(OnInfoMessage);
// Line below release all Errors/PRINT output from command. Command is now
// not collecting them so memory is not growing.
this._connection.FireInfoMessageEventOnUserErrors = true;
SqlCommand cmd = this._connection.CreateCommand();
// In this case Timeout will never occur
cmd.CommandTimeout = 15;
cmd.CommandType = CommandType.StoredProcedure;
command.CommandText = 'InfiniteLoop';
//Line below throws OutOfMemoryException
cmd.ExecuteNonQuery();
cmd.Dispose();
this._connection.InfoMessage -= new SqlInfoMessageEventHandler(OnInfoMessage);
}
void OnInfoMessage(object sender, SqlInfoMessageEventArgs e)
{
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString()+": "+ e.Message);
}