Подтвердить что ты не робот

Как я могу обнаружить, что TadoConnection потерял связь с сервером?

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

Еще один вариант, который я пробовал, - это TTimer и выполнение такого запроса

SELECT 1 RESULT FROM DUAL

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

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

4b9b3361

Ответ 1

Я вижу таблицу DUAL. Значит, вы используете Oracle:)

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

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

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

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

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

Вид этого...

Ответ 2

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

С уважением.

Ответ 3

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

Ответ 4

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