Как переподключиться к той же UIBDatabase + UIBTransaction после потери сети?

У нас есть приложение Delphi7 + UIB + Firebird 2.5 для пиццерий, стабильно работающее в проводных сетях.
Но по Wi-Fi, (работает с планшетными компьютерами Win8/Win10), если соединение разорвано, UIBDatabase не может переподключиться автоматически.

(В настоящее время мы реконструируем все приложение, чтобы удалить «остатки IBX», но после обновления UIB до последней версии, похоже, проблемы еще хуже!)

После типичной потери соединения появляется сообщение об ошибке. является:

Project ...exe raised exception class EUIBError with message 'connection rejected by remote interface
Connection not established
GDS Code: 335544421 - SQL Code: -923 - Error Code: 101'. Process stopped. 

Даже если я попытаюсь закрыть текущее соединение с помощью .IsConnected:=False или .CancelAbort, он больше не сможет снова подключиться:

Project ...exe raised exception class EUIBError with message 'invalid statement handle
Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements
GDS Code: 335544485 - SQL Code: -901 - Error Code: 165'. Process stopped. Use Step or Run to continue.

Поэтому, что бы мы ни делали, мы не можем восстановить соединение!

В худшем случае TabletPC переходит в спящий режим, потому что соединение определенно разорвано, но компонент считает, что он все еще находится в сети. Требуется минимум 8 секунд, чтобы понять, что запрос не может быть выполнен.

Мы пытались запустить TTimer раньше, чтобы принудительно отменить операцию через 2000 мс, но это событие никогда не запускается.

Поэтому мне интересно:

  • Есть ли способ правильно обрабатывать эти случаи?
  • Ни у кого больше нет таких проблем? (Красный здесь все связанные темы, найдено только 1 аналогичный с 0 решением .)
  • Можно ли загрузить текущий компонент UIB из здесь, он не стабильный? (С трудом компилировался под D7 из-за множества ошибок несовместимости SynEdit!)
  • Почему событие .OnConnectionLoss запускается только после повторной попытки повторного подключения?
  • Можно ли снова подключиться к:
    ТАКОЙ ЖЕ транзакции,
    завершить запрос
    и правильно зафиксировать и закрыть?
    (Поскольку мы можем прочитать транзакцию ID от Firebird.) ... поэтому серверу не нужно держать его открытым более 2 часов.

person SzakiLaci    schedule 07.09.2019    source источник
comment
Если вы все равно все делаете заново, вам следует серьезно подумать о соединении без сохранения состояния, таком как REST.   -  person Jerry Dodge    schedule 07.09.2019
comment
Как я уже писал: мы реконструируем старый безостановочный способ IBX на новый способ. Теперь он вообще не работает стабильно. Я подключаюсь только для проверки изменений. Только после получения события FB. Все данные хранятся в памяти с использованием потокобезопасных переменных.   -  person SzakiLaci    schedule 07.09.2019
comment
@JerryDodge ‹OFF› Мы пытались разработать REST API + мобильное приложение, потратив 4 года и миллионы. Ушло все в хлам. Больше не надо. Нам нужно решение вышеуказанной проблемы. ‹/OFF›   -  person SzakiLaci    schedule 07.09.2019
comment
Если бы я был в вашей ситуации, я спрашиваю себя, что бы я сделал? Первое, что я бы сделал, это изменил бы компоненты моей базы данных. В Delphi 7 вы можете использовать IBX или DBX с драйвером Upscene Productions Firebird. (Вы можете найти его на обратном пути)   -  person nolaspeaker    schedule 07.09.2019


Ответы (1)


Ошибка 1:
Случайно ввел tpConsistency вместо tpConcurrency на 1 месте около 50.
Это заблокировало всю таблицу, поэтому обратное подключение было невозможно

Ошибка 2:
рекомендуется установить myTransaction.DefaultAction := etmRollback;

Ошибка 3:

Неверный код UIB uiblib.pas.

  • Переменные FLockTimeout и LockTimeout должны быть целыми!
  • ИСПРАВЛЕННЫЙ код параметра:
    function CreateTRParams(Options: TTransParams; const LockRead, LockWrite: string{$IFDEF FB20_UP}; LockTimeout: integer{$ENDIF}): RawByteString;
    ...
      begin
      {$IFDEF FB20_UP}
      if LockTimeout = 0 then
          Exclude(Options, tpLockTimeout)
      else begin // -1 = infinite,   1..2048M = seconds
          Exclude(Options, tpnoWait);
          Include(Options, tpWait );
          Include(Options, tpLockTimeout);
      end;
      {$ENDIF}
      if Options = [tpConcurrency,tpWait,tpWrite] then
        result := ''
      else
        begin
          Result := isc_tpb_version3;
          for tp := Low(TTransParam) to High(TTransParam) do
            if (tp in Options) then
            begin
              case tp of
                tpLockRead   : ParseStrOption(tpc[tp], AnsiString(LockRead));
                tpLockWrite   : ParseStrOption(tpc[tp], AnsiString(LockWrite));
              {$IFDEF FB20_UP}
                tpLockTimeout : 
    //old code: PAnsiChar(@LockTimeout)[0] + PAnsiChar(LockTimeout)[1]; << [1] causing AV error
                  case LockTimeout of
                    -1     : Result := Result + tpc[tp] + #4#127#255#255#255;
    //               0     : Result := Result + tpc[tp] + #1#0; // this would be invalid
                    1..255: Result := Result + tpc[tp] + #1 + AnsiChar(Byte( LockTimeout and $FF));
                  else //256..32k
                            Result := Result + tpc[tp] + #2 + AnsiChar(Byte((LockTimeout div $FF) and $FF)) + AnsiChar(Byte(LockTimeout and $FF));
                  end;
              {$ENDIF}
              else
                Result := Result + tpc[tp];
              end;
            end;
        end;
    end;

Запрос функции 4
Не удалось найти решение для повторного подключения к ТОЙ ЖЕ транзакции, которая была ранее потеряна.

person SzakiLaci    schedule 10.09.2019
comment
Вы не сможете повторно подключить ту же самую ранее потерянную транзакцию, потому что Firebird обнаружит потерю соединения и прервет транзакцию. Вы должны повторно подключиться и открыть новую транзакцию. Насколько я понимаю, вы используете длительную транзакцию, это серьезный недостаток дизайна. Ваши транзакции должны быть как можно короче. - person ZeDalaye; 26.09.2019