我需要检测一下 TAdoConnection 组件已丢失与服务器的连接。我试过用过 OnDisconnect 事件但仅在调用Close方法或Connected属性设置为false时触发。
我尝试过的另一个选择是使用 TTimer 并执行这样的查询
SELECT 1 RESULT FROM DUAL
在OnTimer事件中,捕获发生的任何异常。
有没有更好的选择来检测连接丢失?
我需要检测一下 TAdoConnection 组件已丢失与服务器的连接。我试过用过 OnDisconnect 事件但仅在调用Close方法或Connected属性设置为false时触发。
我尝试过的另一个选择是使用 TTimer 并执行这样的查询
SELECT 1 RESULT FROM DUAL
在OnTimer事件中,捕获发生的任何异常。
有没有更好的选择来检测连接丢失?
我看到了DUAL表。意思是,你使用的是Oracle :)
对于大多数(全部?)客户端/服务器DBMS,除了向DBMS请求某些操作之外,没有办法检测到连接丢失。并且有很多原因,为什么连接会丢失。可能是网络故障,可能是......,可能是DBA关闭了一个DB。
许多DBMS API(包括Oracle OCI)都具有特殊功能,允许ping DBMS。 “ping”是对DBMS的最小可能请求。上面的SELECT比这样的ping需要更多的工作。
但并非所有数据访问组件(包括ADO)都允许使用DBMS API ping调用ping DBMS。然后你必须使用一些SQL命令。因此,上面的SELECT与ADO是正确的。其他选项 - BEGIN NULL;结束;。它可能使用较少的DBMS资源(不需要优化器,不需要描述结果集等)。
TTimer没问题。查询应在线程中执行,其中使用相应的连接。虽然不是必须的,但这是一个不同的问题。
当连接丢失时,潜在的问题可能是关闭连接。由于DBMS API可能处于失败状态,因此连接关闭可能引发异常。
有点......
@Dimitry的回答非常好。如果您的应用程序知道connectino是否丢失是至关重要的,那么TTimer方法(具有最小的操作)。
如果您只是想知道语句因“通信丢失”而失败,您可以使用Application.OnException事件并检查Exception属性。
我使用ApplicationEvents组件将以下代码作为示例。只是一个有想法的草案,不适合生产。
uses
ComObj;
procedure TForm2.ApplicationEvents1Exception(Sender: TObject; E: Exception);
var
EO: EOleException;
begin
if E is EOLEException then
begin
EO := EOleException(E);
//connection error (disconnected)
if EO.ErrorCode = E_FAIL then
begin
try
try
ADOConnection1.Close;
except
;
end;
ADOConnection1.Open;
ShowMessage('Database connection failed and re-established, please retry!');
except
on E:Exception do
ShowMessageFmt('Database connection failed permanently. '
+ 'Please, retry later'#13'Error message: %s', [E.Message]);
end;
end
else
ShowMessage(E.Message + ' ' + IntToStr(EO.ErrorCode));
end
else
ShowMessage(E.ClassName + #13 + E.Message);
end;
最好的祝福。
我在连接池上遇到同样的问题。我开发了一个TADOSQLConnectionPool类来帮助重用DB连接的线程连接。当我想为一个线程分配连接时,我试图通过运行最小作业“选择1”来检查它的健康状况。通过这种方式,我将确定连接。如果失败,我将处置所有连接以在下一个请求时重新创建。
这是放弃ADO并使用DBX的原因之一。 Ado架构是基于服务器游标的,这个requeris不会随时丢失与服务器的连接。如果在某些情况下连接丢失,则连接将无法再次启动。另一方面,由于其断开连接,DBX能够重新连接到永远。