【问题标题】:Deallocation of SqlDataReaderSqlDataReader 的释放
【发布时间】:2012-05-23 02:55:52
【问题描述】:

我有一个承包商,当我们执行 sql 查询时,他到处写这样的代码:

sql.Append(string.Format("SELECT TableId FROM ps_SavedTables WHERE guid = '{0}'", guid));

        using (IDataReader reader = SqlHelper.GetDataReader(sql.ToString())) {
            if (reader.Read()) {
                result = reader.IsDBNull(0) ? string.Empty : reader[0].ToString();
            }
            //CDW added to close SqlDataReader
            reader.Close();
        }

GetDataReader 类位于 App_Code 帮助文件中,声明如下:

 public static SqlDataReader GetDataReader(string sql) {
        return GetDataReader(sql, DefaultConnectionString);
    }

    public static SqlDataReader GetDataReader(string sql, int connectionTime) {
        return GetDataReader(sql, DefaultConnectionString, connectionTime);
    }

    /// <summary>
    /// Executes DB command ExecutedReader and returns the DataReader
    /// </summary>
    /// <param name="sql">SQL statement(s) to be used with DB command</param>
    /// <param name="connectionString">Database connection string</param>
    /// <returns>DataReader containing results of supplied SQL statement(s)</returns>
    public static SqlDataReader GetDataReader(string sql, string connectionString) {
        lock (_lock) {
            SqlConnection connection = null;
            try {
                connection = GetConnection(connectionString);
                //connection.Open();
                using (SqlCommand cmd = new SqlCommand(sql, connection)) {
                    WriteDebugInfo("GetDataReader", sql);
                    return cmd.ExecuteReader(CommandBehavior.CloseConnection);
                }
            }
            catch (Exception e) {
                if (connection != null)
                    connection.Dispose();
                throw new DataException(sql, connectionString, e);
            }

        }
    }

然后我在本地运行我的代码(它为统计数据执行了大量 SQL)并在两个不同的浏览器中运行相同类型的东西,其中 1 个浏览器总是在这里崩溃:

Server.ScriptTimeout = 300;
        string returnCode = string.Empty;
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MainDll"].ToString())) {
            connection.Open();
            using (SqlCommand command = new SqlCommand(sql.ToString(), connection)) {
                command.CommandType = CommandType.Text;
                command.CommandTimeout = 300;
                returnCode = (string)command.ExecuteScalar();
                Dispose();
            }
            Dispose();
        }

堆栈是这样的:

.NET Framework execution was aborted by escalation policy because of out of memory. 
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
System.InvalidOperationException: 
  at System.Data.SqlClient.SqlInternalConnectionSmi.ValidateConnectionForExecute(SqlCommand command)
  at System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command)
  at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
  at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
  at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
  at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
  at System.Data.SqlClient.SqlCommand.ExecuteReader()
  at PowerStatRegression.share.JbLog.SendResultSet(String str, SqlConnection conn)
  at StoredProcedures.SavePowerStatErrors(ApplicationContext app, SqlString strUID, Int32 seqId, List`1 errors, Int32 errorType)
  at StoredProcedures.CreatePowerStatCorr(SqlString strUID, Int32 seqId, Int32 flagProgress)
  at StoredProcedures.SpCreatePowerStatCorr(SqlString strUID, Int32 seqId, Int32 flagProgress)

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Data.SqlClient.SqlException: .NET Framework execution was aborted by escalation policy because of out of memory. 
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
System.InvalidOperationException: 
  at System.Data.SqlClient.SqlInternalConnectionSmi.ValidateConnectionForExecute(SqlCommand command)
  at System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command)
  at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
  at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
  at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
  at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
  at System.Data.SqlClient.SqlCommand.ExecuteReader()
  at PowerStatRegression.share.JbLog.SendResultSet(String str, SqlConnection conn)
  at StoredProcedures.SavePowerStatErrors(ApplicationContext app, SqlString strUID, Int32 seqId, List`1 errors, Int32 errorType)
  at StoredProcedures.CreatePowerStatCorr(SqlString strUID, Int32 seqId, Int32 flagProgress)
  at StoredProcedures.SpCreatePowerStatCorr(SqlString strUID, Int32 seqId, Int32 flagProgress)


Source Error: 


Line 705:                    command.CommandType = CommandType.Text;
Line 706:                    command.CommandTimeout = 300;
Line 707:                    returnCode = (string)command.ExecuteScalar();
Line 708:                    //Dispose();
Line 709:                }


Source File: c:\PowerStats\datalab\powerstats\output.aspx.cs    Line: 707 

Stack Trace: 

    [SqlException (0x80131904): .NET Framework execution was aborted by escalation policy because of out of memory. 
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
System.InvalidOperationException: 
   at System.Data.SqlClient.SqlInternalConnectionSmi.ValidateConnectionForExecute(SqlCommand command)
   at System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command)
   at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader()
   at PowerStatRegression.share.JbLog.SendResultSet(String str, SqlConnection conn)
   at StoredProcedures.SavePowerStatErrors(ApplicationContext app, SqlString strUID, Int32 seqId, List`1 errors, Int32 errorType)
   at StoredProcedures.CreatePowerStatCorr(SqlString strUID, Int32 seqId, Int32 flagProgress)
   at StoredProcedures.SpCreatePowerStatCorr(SqlString strUID, Int32 seqId, Int32 flagProgress)
]
   System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +1950522
   System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +4856715
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +194
   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +1121
   System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +33
   System.Data.SqlClient.SqlDataReader.get_MetaData() +83
   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +293
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +954
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
   System.Data.SqlClient.SqlCommand.ExecuteScalar() +139
   Output.RunTable(String outputType, String _outputDataType) in c:\PowerStats\datalab\powerstats\output.aspx.cs:707
   Output.ProcessPage() in c:\PowerStats\datalab\powerstats\output.aspx.cs:652
   Output.Page_Load(Object sender, EventArgs e) in c:\PowerStats\datalab\powerstats\output.aspx.cs:644
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627




--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.5456; ASP.NET Version:2.0.50727.5456 

为什么 SqlDataReader 没有被正确释放?

【问题讨论】:

  • 这在其他票上很有趣,人们想要更多代码
  • 他们想要的是票长代码而不是墙长代码
  • 你是来帮忙的吗
  • 实际崩溃在哪里?异常在 SqlCommand.ExecuteReader 中说明,但我认为您所说的代码块崩溃调用 ExcecuteScaler。
  • DataReader 看起来并没有被丢弃在任何地方,它应该被丢弃。我对为什么代码的结构方式有点茫然。为什么会发生锁定?为什么这个人使用 string.Format() 编写 SQL 查询?我不会再雇用这个承包商了。

标签: c# asp.net .net sql-server-2005 sqldatareader


【解决方案1】:

“锁定”语句是否意味着您正在多个线程中使用这些东西?
甚至不要尝试在线程之间共享 ADO .NET 对象——它们不是线程安全的……似乎有多个线程同时创建读取器实例。

【讨论】:

  • 同意。每个线程都需要自己的 SqlConnection/SqlCommand/DataReader 实例。
  • @chris: 1) 如果是这样,那么“锁”的用途是什么? 2) 向我们展示 PowerStatRegression.share.JbLog.SendResultSet 方法的代码。 3) 命名空间“StoredProcedures”提示 SQL Server 端的 CLR 程序集。我错了吗? 4) 如果我是对的,App_Code 类是否驻留在该程序集中?
【解决方案2】:

我认为锁在错误的级别...锁需要在读者级别。释放锁后正在使用打开的阅读器。

【讨论】:

  • 打开阅读器前获取,关闭阅读器后释放
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
相关资源
最近更新 更多