DBNETLIB ConnectionWrite时自动恢复常规网络错误导致在Delphi应用程序中ADO连接脱机?

问题描述 投票:7回答:3

谷歌搜索此ADO错误消息表明它在ASP.NET开发中经常遇到,但是我在Delphi应用程序中何时出现它却没有太多提及。我们有一些客户站点遇到瞬态网络问题,这是有症状的错误消息。我们可以在办公室测试中轻松复制它;只要在您的delphi TADOConnection对象连接到该服务器实例上的数据库时关闭MS SQL Server服务,您就会收到此异常:

   [DBNETLIB][ConnectionWrite (send()).]General network error. Check your network documentation.

是,捕获此异常,您知道(或对吗?)已发生此错误。除了这是一个800 KLOC +应用程序外,数据库操作周围有10,000个try-except块,其中任何一个都可能因此错误而失败。

TADOConnection有一些错误事件,在这种情况下都不会触发。但是,一旦发生这种情况,ADO连接本身就会发生故障,即使您重新启动SQL数据库,TADOConnection.Connected仍为true,但这是对您的谎言。它确实处于故障状态。

那么,我的问题是:

您能以比进入10,000个单独的try-except块并设置一些全局“重新连接ADO全局变量”少的工作量来检测此故障状态并从中恢复吗?

我希望有一种方法可以进入TADOConnection.ConnectionObject(基础的原始OLEDB COM ADO对象)并在开始新查询时检测到此故障情况,以便我们可以重置ADOConnection并继续下一次我们运行一个查询。因为我们的代码组织得比在10行演示应用程序中能做到的要容易得多,所以可以让我们“在失败后”检测到此问题。

This other SO question询问为什么会发生,这就是我要的[[not,请不要给我“预防”的答案,我已经知道了,我正在寻找恢复和发现-落后的ADO连接技术,而不是捕获异常。实际上,这是例外出错的一个很好的例子。在这种故障模式下,ADO是一个schrodingers-cat对象。

我知道MS知识库文章,以及Internet上浮动的各种解决方案。一旦错误状况(在我们的情况下通常是短暂的)已经清除,我就在不丢失客户数据的情况下询问恢复。这意味着我们将冻结应用程序,向客户显示异常,并且当客户单击“重试”或“继续”时,我们将尝试修复并继续。请注意,我们现有的代码会执行一百万次“ try-except-log-and-continue”代码,这会妨碍我们的工作,所以我希望有人回答说,针对未处理的异常的Application处理程序是最好的方法,但可悲的是我们不能使用它。但是,我真的希望可以检测到冻结/故障/死ADO连接对象。

这是我所拥有的:

try if fQueryEnable and ADOConnection1.Connected then begin qQueryTest1.Active := false; qQueryTest1.Active := true; Inc(FQryCounter); Label2.Caption := IntToStr(qQueryTest1.RecordCount)+' records'; end; except on E:Exception do begin fQueryEnable := false; Memo1.Lines.Add(E.ClassName+' '+E.Message); if E is EOleException and Pos('DBNETLIB',E.Message)>0 then begin ADOConnectionFaulted := boolean; { Global variable. } end; raise; end; end;

上述解决方案的问题是,我需要在应用程序中复制并粘贴大约10,000个位置。
sql-server delphi ado
3个回答
8
投票
没有人回答这个问题,我认为进行一些后续跟踪会有所帮助。

这是我所学到的:

  • 在可靠的情况下,您无法在测试环境中重现此常规网络错误。就是说,我们正在处理“不可复制的结果”,许多开发人员在此进入恶意的黑客程序,试图“ monkeypatch”他们损坏的系统。
  • 当SQL库给出“常规网络错误”时,修复基本故障始终比在代码中更胜一筹。从未显示过修复的可能,因为通常这意味着“网络太不可靠,TCP本身已经放弃了传递数据的责任”,这种情况发生在以下情况:

    • 您的网络电缆不正确。
    • 您在网络上有重复的IP地址。
    • 您有对决的DHCP服务器,每个服务器处理不同的默认网关。
    • 您有本地以太网网段,它们之间的连通性很差。
    • 您的以太网交换机或集线器出现故障。
    • 您正被防火墙故障间歇性地阻止。
    • 您的客户可能已经更改了他们网络上的某些内容,现在可能无法使用您的软件。 (最后这件事实际上比您想象的要多)
    • 某人可能已经使用cliconfg或特定于单个工作站注册表设置的其他客户端配置元素配置了SQL别名,并且此本地配置可能会导致不良行为,难以诊断,并且可能仅限于大型网络上的一个或几个工作站。

以上均不能在TCP或SQL级别检测到并报告。当SQL最终放弃,并给出此“常规网络错误”时,我的软件发出的大量哄哄声将使它无法放弃,即使这样做,我也会做“ try / except” / ignore”反模式。该错误非常严重,我们应该将其完全提高给用户,将其记录到错误日志中的磁盘上,放弃(退出程序),并告诉用户网络连接已断开。


2
投票
我也看到这种情况是由于编码错误造成的。.

如果您使用连接打开记录集,并且在第一个连接未关闭的情况下将同一连接循环用于另一个记录集,则会导致类似的错误。

在Web应用程序上的另一个极少数情况是在应用程序池回收时,您可能会收到类似的错误。

我们在同一台服务器上有不同的站点,在该站点中,我注意到使用相同的应用程序但使用不同的自定义设置,只有一个站点导致了此问题。这导致了上述发现。

此博客帮助我发现了问题:

http://offbeatmammal.hubpages.com/hub/Optimising_SQL_Server


1
投票
这里的代码检测到断开事件触发,并使用计时器重新连接。

请检查下一个代码:

unit uDM; interface uses SysUtils, Classes, DB, ADODB, Vcl.ExtCtrls; type TDM = class(TDataModule) ADOConnection: TADOConnection; ConnectionTimmer: TTimer; procedure ADOConnectionDisconnect(Connection: TADOConnection; var EventStatus: TEventStatus); procedure ConnectionTimmerTimer(Sender: TObject); private { Private declarations } public { Public declarations } end; var DM: TDM; implementation {$R *.dfm} procedure TDM.ADOConnectionDisconnect(Connection: TADOConnection; var EventStatus: TEventStatus); begin if eventStatus in [esErrorsOccured, esUnwantedEvent] then ConnectionTimmer.Enabled := True; end; procedure TDM.ConnectionTimmerTimer(Sender: TObject); begin ConnectionTimmer.Enabled := False; try ADOConnection.Connected := False; ADOConnection.Connected := True; except ConnectionTimmer.Enabled := True; end; end; end.

© www.soinside.com 2019 - 2024. All rights reserved.