【问题标题】:How to address SqlConnection being closed from inside ExecuteReader?如何解决从 ExecuteReader 内部关闭的 SqlConnection?
【发布时间】:2013-01-09 06:15:25
【问题描述】:

我有一个开放的SqlConnection 和这样的代码:

using (var transaction = connection.BeginTransaction()) {
   using (var command = connection.CreateCommand()) {
       command.Transaction = transaction;
   command.CommandText = "MyQueryText";
       using( var reader = command.ExecuteReader() ) {
           //read data
       }
   }
}

I've been experiencing some "impossible code" symptoms 并订阅了SqlConnection.StateChange 事件,现在我发现在某些时候使用以下堆栈调用事件(状态从Open 更改为Closed):

at MyHandler.onStateChange(Object sender, StateChangeEventArgs e)
at System.Data.ProviderBase.DbConnectionInternal.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Close()
at System.Data.SqlClient.SqlInternalConnectionTds.BreakConnection()
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.ReadByte()
at System.Data.SqlClient.SqlDataReader.SetMetaData(_SqlMetaDataSet metaData, Boolean moreInfo)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, 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()
// my code calling `ExecuteReader()`

所以运行时遇到一些随机错误(我猜是网络连接问题)并关闭连接,然后将关闭的阅读器对象返回给我的代码,我尝试使用返回的阅读器产量 InvalidOperationException

我需要以某种方式解决它。显然会发生随机网络错误。我的代码中有重试逻辑,可以处理网络问题引发的SqlExceptions,但在这里我面对的是一个封闭的读者,然后是InvalidOperationException

我的第一个想法是编写我自己的ExecuteReader(),它将调用本机ExecuteReader(),检查是否返回了封闭的阅读器,如果发生这种情况,则抛出一个新的ClosedReaderReturnedException,我还将更改重试代码,以便它也会对此类异常做出反应并重新运行查询。

我的解决方案好吗?有没有更好的解决方案?

【问题讨论】:

  • 在连接网站上提交错误。如果你从你的活动中抛出会发生什么?您的异常会使其备份到执行阅读器吗?
  • @AbdElRaheim:我会提交一个错误,但修复它需要很长时间,或者他们甚至会“按设计”关闭它,我现在需要一个解决方法。这不能可靠地复制,所以我不能真正彻底地测试它。
  • 调用executereader后是否可以检查连接状态?也许制作一个扩展方法,将在命令上调用执行阅读器,然后检查连接状态。也许还有一个 read() 方法可以做同样的检查
  • @AbdElRaheim:这或多或少是我的建议,不是吗?
  • 哦。这是一个很好的解决方案:)

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


【解决方案1】:

是否存在基于任何异常(而不是特定 SqlException)的重试逻辑的问题?我假设由于编程错误导致的异常最终会在测试阶段被发现,并且严重的(例如 SO)异常无论如何都不会被 catch 块捕获,因此用于重试逻辑的通用异常块是可以接受的。

如果不是,那么包装ExecuteReader 的解决方案可能是个好主意。考虑到这是 documentated 的行为,您还需要注意 ExecuteReader 方法可能抛出的其他异常 - 因此您可能需要预料到 IOExceptionObjectDisposedException 除了 InvalidOperationException

【讨论】:

  • 重试任何异常都是一个坏主意 - 它可能会引发对外部服务的毁灭性请求风暴并瘫痪一切。
猜你喜欢
  • 2020-11-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-08
相关资源
最近更新 更多