谷歌搜索此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个位置。
这是我所学到的:
cliconfg
或特定于单个工作站注册表设置的其他客户端配置元素配置了SQL别名,并且此本地配置可能会导致不良行为,难以诊断,并且可能仅限于大型网络上的一个或几个工作站。以上均不能在TCP或SQL级别检测到并报告。当SQL最终放弃,并给出此“常规网络错误”时,我的软件发出的大量哄哄声将使它无法放弃,即使这样做,我也会做“ try / except” / ignore”反模式。该错误非常严重,我们应该将其完全提高给用户,将其记录到错误日志中的磁盘上,放弃(退出程序),并告诉用户网络连接已断开。
如果您使用连接打开记录集,并且在第一个连接未关闭的情况下将同一连接循环用于另一个记录集,则会导致类似的错误。
在Web应用程序上的另一个极少数情况是在应用程序池回收时,您可能会收到类似的错误。
我们在同一台服务器上有不同的站点,在该站点中,我注意到使用相同的应用程序但使用不同的自定义设置,只有一个站点导致了此问题。这导致了上述发现。
此博客帮助我发现了问题:
请检查下一个代码:
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.