Как я могу определить, что TadoConnection потерял связь с сервером? - PullRequest
11 голосов
/ 18 февраля 2010

Мне нужно определить, когда компонент TAdoConnection потерял соединение с сервером. Я пытался использовать событие OnDisconnect , но оно срабатывает только при вызове метода Close или если для свойства Connected установлено значение false.

Другой вариант, который я попробовал, - это использовать TTimer и выполнить запрос, подобный этому

SELECT 1 RESULT FROM DUAL

в событии OnTimer, перехватывая все возникающие исключения.

Есть ли лучший способ обнаружить, что соединение было потеряно?

Ответы [ 4 ]

11 голосов
/ 18 февраля 2010

Вижу ДВОЙНУЮ таблицу. Значит, вы используете Oracle:)

Для большинства (всех?) Клиент-серверных СУБД нет способа обнаружить потерянное соединение, кроме как попросить СУБД о каком-либо действии. И есть много причин, почему связь теряется. Может быть сбой в сети, может быть ..., может быть, администратор БД отключил БД.

Многие API-интерфейсы СУБД, в том числе Oracle OCI, имеют специальные функции, позволяющие пинговать СУБД. «Пинг» - это наименьший возможный запрос к СУБД. Вышеуказанный SELECT требует гораздо больше работы, чем такой пинг.

Но не все компоненты доступа к данным, включая ADO, позволяют пинговать СУБД с помощью вызова ping API СУБД. Затем вы должны использовать какую-то команду SQL. Таким образом, вышеупомянутый SELECT является правильным с ADO. Другой вариант - НАЧАТЬ НУЛЬ; КОНЕЦ;. Возможно, используется меньше ресурсов СУБД (нет необходимости в оптимизаторе, нет необходимости описывать набор результатов и т. Д.).

TTimer в порядке. Запрос должен выполняться в потоке, где используется соответствующее соединение. Не обязательно, но это другой вопрос.

Потенциальная проблема может заключаться в закрытии соединения, когда соединение теряется. Поскольку закрытие соединения может вызвать исключение, поскольку API СУБД может находиться в состоянии сбоя.

Вроде того ...

3 голосов
/ 18 февраля 2010

@ Димитрий ответ очень хороший.Если для вашего приложения важно знать, потерян ли 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;

С уважением.

0 голосов
/ 16 марта 2014

У меня такая же проблема в пуле соединений. Я разработал класс TADOSQLConnectionPool, чтобы помочь повторно использовать соединение для работы потоков БД. Когда я хочу назначить соединение потоку, я попытался проверить его работоспособность, запустив минимальное задание как «Выбрать 1». Таким образом, я буду уверен в соединении. Если оно не удастся, я избавлюсь от всех соединений для воссоздания при следующем запросе.

0 голосов
/ 19 февраля 2010

Это одна из причин отказаться от ADO и использовать DBX. Архитектура Ado основана на серверных курсорах, и это требует не терять соединение с сервером в любое время. Если в некоторых случаях соединение будет потеряно, оно не сможет восстановиться. С другой стороны, DBX может переподключаться почти всегда из-за своей отключенной архитектуры.

...