Я должен обнаружить, когда компонент TAdoConnection потерял соединение с сервером. Я попытался использовать событие OnDisconnect, но это только стреляет, когда Близкий метод называют, или свойство Connected имеет значение false.
Другая опция, которую я попробовал, использует TTimer и выполняет запрос как это
SELECT 1 RESULT FROM DUAL
в событии OnTimer, ловя любое исключение, которое происходит.
Существует ли более оптимальный вариант обнаружить, что соединение было потеряно?
Я вижу таблицу DUAL. Значит, вы используете Oracle :)
Для большинства (всех?) Клиент-серверных СУБД нет другого способа определить, что соединение потеряно, кроме как запросить у СУБД какое-то действие. Причин потери связи очень много. Может быть сбой сети, может быть ..., может быть администратор базы данных отключил БД.
Многие API СУБД, в том числе Oracle OCI, имеют специальные функции, позволяющие проверять связь с СУБД. «Пинг» - это минимально возможный запрос к СУБД. Вышеупомянутый SELECT требует гораздо больше работы, чем такой ping.
Но не все компоненты доступа к данным, включая ADO, позволяют пинговать СУБД, используя вызов ping API СУБД. Затем вам нужно использовать какую-то команду SQL.Итак, приведенный выше SELECT верен для ADO. Другой вариант - BEGIN NULL; КОНЕЦ;. Возможно, он использует меньше ресурсов СУБД (нет необходимости в оптимизаторе, нет необходимости описывать набор результатов и т. Д.).
TTimer в порядке. Запрос должен выполняться в потоке, где используется соответствующее соединение. Хотя не обязательно, но это другой вопрос.
Потенциальная проблема может заключаться в закрытии соединения при потере соединения. Поскольку закрытие соединения может вызвать исключение из-за того, что API СУБД может находиться в состоянии сбоя.
Что-то вроде того ...
@Dimitry, ответ очень хорош. Если для вашего приложения важно знать, потеряно ли соединение, используйте подход 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;
С уважением.
Это одна из причин отказаться от ADO и использовать DBX. Архитектура Ado основана на серверном курсоре, и это необходимо для того, чтобы не терять соединение с сервером в любое время. Если при некоторых обстоятельствах соединение будет потеряно, оно не сможет снова установить соединение. С другой стороны, DBX может восстановить соединение почти всегда из-за своей отключенной архитектуры.