超时异常会导致SqlDataReader关闭吗?

11

我试图从数据库中提取一些二进制数据并将其写入PDF文件。 大多数情况下,这都进行得很顺利,但是偶尔会出现一个数据行导致特定的错误-

超时已过期。 在操作完成之前超时时间已过或服务器未响应。

请记住,这仅发生在少数几行上,而且永远不是随机的。 相同的行始终引发异常。 我不太确定为什么会引发异常,但是我可以跳过引起问题的行并继续进行。 然而,我的问题是当我捕获异常然后尝试继续到下一行时,我遇到了另一个异常-

无效操作异常-尝试在读取器关闭时调用Read方法。

这是否意味着读取器遇到异常后会自动关闭? 如何在没有任何问题的情况下继续进行下一行?

        while (sdrReader.Read()) // Second exception happens here
        {
            try
            {
                byte[] byteData = new Byte[(sdrReader.GetBytes(0, 0, null, 0, int.MaxValue))]; // first exception happens here
                sdrReader.GetBytes(0, 0, byteData, 0, byteData.Length);
                string strOutputFileName = sdrReader.GetInt32(1).ToString() + ".pdf";
                msMemoryStreams = new MemoryStream();
                msMemoryStreams.Write(byteData, 0, byteData.Length);
                byte[] byteArray = msMemoryStreams.ToArray();

                msMemoryStreams.Flush();
                msMemoryStreams.Close();

                writeByteArrayToFile(byteData, txtFilesPath.Text + "\\" + strOutputFileName);
            }
            catch (Exception e)
            {
                Logger.Write("Document failed to convert: " + e.Message);
            }
        }

如您所请求的那样,以下是堆栈跟踪:

   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   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.ReadBuffer()
   at System.Data.SqlClient.TdsParserStateObject.ReadByteArray(Byte[] buff, Int32 offset, Int32 len)
   at System.Data.SqlClient.TdsParser.ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.ReadColumnData()
   at System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout)
   at System.Data.SqlClient.SqlDataReader.GetSqlBinary(Int32 i)
   at System.Data.SqlClient.SqlDataReader.GetBytesInternal(Int32 i, Int64 dataIndex, Byte[] buffer, Int32 bufferIndex, Int32 length)
   at System.Data.SqlClient.SqlDataReader.GetBytes(Int32 i, Int64 dataIndex, Byte[] buffer, Int32 bufferIndex, Int32 length)
   at Pdf2Rtf.Form1.Read() in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Form1.cs:line 77
   at Pdf2Rtf.Form1.btnRead_Click(Object sender, EventArgs e) in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Form1.cs:line 24
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at Pdf2Rtf.Program.Main() in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Program.cs:line 18
   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
2个回答

17

看起来你的SqlCommand正在超时-当你调用ExecuteReader时,相关的命令仍然保持打开状态,并且将容易受到超时的影响,直到你完成读取。正如在SqlCommand.CommandTimeout文档中所述:

此属性是命令执行期间或处理结果期间所有网络读取的累计超时时间。即使返回了第一行,仍可能发生超时,不包括用户处理时间,只包括网络读取时间。

当命令超时时,它会关闭读取器,此时你无法恢复。

首先要尝试解决这个问题的方法是大幅提高CommandTimeout的值,以确保你可以继续进行。

接下来,如果还没有这样做,使用允许你指定CommandBehaviorExecuteReader重载可能有所帮助,并传递CommandBehavior.SequentialAccess(根据MSDN主题“检索大型数据(ADO.NET)”中的建议)。

最后,你也可以尝试将读取分成记录块。


事实证明,我所需要的只是增加超时时间(请注意,我不得不将其增加到约10分钟)。 我提取的一些文档非常大!谢谢;) - Paulie

1
如果SQL错误的严重程度小于17,您可以设置SqlConnection.FireInfoMessageEventOnUserErrors = true将异常处理为警告。任何大于严重程度17的错误都会无论如何关闭连接

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接