2013-03-19 41 views
1

我有执行Sql的问题,实际上是SqlServer上的存储过程的简单调用。SqlCommand ExecuteNonQuery抛出OutOfMemoryException

考虑下面SQL存储过程:

CREATE PROCEDURE InfiniteLoop 
    AS 
    BEGIN 
     DECLARE @ixi NUMERIC(38) = 0 
     DECLARE @i NUMERIC(38) = 0 
     WHILE 1 = 1 
     BEGIN 
      SET @i = @i + 1 
      SET @ixi = @ixi * @i 
      PRINT N'some text' 
     END 
    END; 

现在我'调用以这种方式从C#这个程序:

public void CallProcedure() 
{ 
    SqlCommand cmd = this._connection.CreateCommand(); 
    cmd.CommandType = CommandType.StoredProcedure; 
    command.CommandText = 'InfiniteLoop'; 

    //Line below throws OutOfMemoryException 
    cmd.ExecuteNonQuery(); 

    cmd.Dispose(); 
} 

内存真的开始快速增长。几秒钟后抛出异常。 Normaly所有这些代码是用“的try/catch”和“用”的部分,但我简化了这个片段,以显示这个问题直接来自图书馆的SqlClient不从我的代码。

+0

看起来您已经发现了一个关于ExecuteNonQuery实现的有趣观点。但是你的问题是什么? – 2013-03-19 13:10:01

回答

4

经过更多研究,我发现解决方案如何停止OutOfMemoryException并采取预期的TimeoutException。

由于存储过程中使用PRINT,所以这种情况下内存正在增长。 Driever正在收集数据库的默认输出。因此,如果用户没有阅读此内容,则可能会发生OutOfMemoryException。

根据你想要的结果可以使用两种解决方案。当数据库输出是不是对你很重要,当执行需要长期您所期待Timout

第一个是好的。下面摘录解决了这个问题的方式:

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); 
} 
相关问题