W dniu środa, 19 lutego 2014 18:07:30 UTC+1 użytkownik wloochacz napisał:
> W dniu 2014-02-19 14:34,
buni...@gmail.com pisze:
>
> > Witam,
>
> >
>
> > Mam pulę wątków. Dla każdego wątku tworze osobne połączenie z bazą danych (Firebird). Każdy wątek ma swoja transakcję do odczytu ReadOnly oraz tworzone dynamicznie transakcje do zapisu/kasowania zwalniane po danej akcji.
>
> A po co tę transakcję (obiekt klasy TFDTransaction) do zapisu/kasowania
>
> tworzysz dynamicznie i niszczysz po każdej akcji?
Można by utworzyć jeden obiekt TADTransaction do zapisu i startować przed update/delete/inster a potem commit. Wydaje mi się że samo utworzenie obiektu transakcji nie trwa na tyle długo aby to był problem, ale pewnie się mylę.
>
>
> > Bazę tworze w następujący sposób
>
> Nie bazę, tylko connection...
Tak, tworzę obiekt podłączenia do bazy
>
>
>
> > FDataBase := TADConnection.Create(nil);
>
> > FDataBase.LoginPrompt := False;
>
> > FDatabase.ConnectionDefName := C_CONNECTION_NAME;
>
> > FDatabase.OnRecover := prRecoverConnection;
>
> > FDatabase.FormatOptions := ADatabase.FormatOptions;
>
> Uważaj na takie zapisy, akurat w FD zadziała to poprawnie, bo setter
>
> jest napisany tak:
>
> FOptionsIntf.FormatOptions.Assign(AValue);
>
>
>
> Ale gdzie indziej możesz zrobić sobie kuku...
tego jestem świadomy, niemniej dziękuje za wskazówkę.
tak ale najwyraźniej nie doczytałem że mogę tam też inne parametry ustawiać. Tak czy owak "pobieram" je z głównego połączenia. Doczytam i poprawie.
przy próbie wznowienia wątku. Dokładnie chodzi tutaj o serwer HTTP (Indy) i wątki/zadnia TIdThreadWithTask (nadpisane). Czyli gdy dany wątek jest pobierany z TIdSchedulerOfThreadPool do obsługi przychodzącego requesta.
> >
>
> > FConnectionIsRestored := True;
>
> > try
>
> > Self.FDatabase.Ping;
>
> > finally
>
> > FConnectionIsRestored := False;
>
> > end;
>
> A czemu nie tak:
>
> FConnectionIsRestored := Self.FDatabase.Ping;
>
> ??
zmienna FConnectionIsRestored ustawiana jest tylko pota aby jak połączenie się wywali w każdym innym przypadku niż "start/restart" wątku to odrazu ma być zwrócone faFail z eventu FDatabase.OnRecover. W zależności od tego co tam ustawimy tak się dalej potoczą losy próby połączenia. faFail zwraca wyjątek że nie udało się nawiązac połączenia z bazą danych. Dla faRetry FD próbuje wznowić połączenie. Mam tam licznik aby próbował powiedzmy 3 razy potem wylotka
>
>
>
> > Zakładam że jak ping przejdzie to jest połączenie z bazą i wątek może działać.
>
> Nie.
>
> Ping zawsze przejdzie i nie wywoła wyjątku, Ping jest funkcją która
>
> zwraca Boolean.
Tutaj się nie zgodzę. Tak samo jak Open dla Query tak samo PING wywołuje event OnRecover i to my decydujemy co tam się stanie.
>
>
>
> Naprawdę, dokumentacja nie gryzie:
>
> "The Ping method checks whether a connection to a DBMS server is alive.
>
> When the connection is dead and ResourceOptions.AutoReconnect is True,
>
> then an automatic reconnection is attempted. When a connection is
>
> inactive, the Ping method will try to open a connection."
>
>
>
>
>
> > w każdym innym przypadku powinien polecić błąd. Czyli wątek nie obsłuży już tego "zlecenia".
>
> Jak wywołasz tam Raise to błąd może i poleci...
pisząc wyjątek miałem na myśli wywołanie faFail (jak to wyżej pisałem )
>
>
>
> > Ale niestety wznawianie połączenia nie działa jak należy.
>
> No popatrz - a mi działa i to jak należy.
>
>
>
> > Ping po komunikatach (debuger) przechodzi dalej ale niestety pierwsze otwarcie query zawiesza się.
>
> Bo nie sprawdzasz, czy ping zwrócił True czy False.
>
> Zwrócił Ci False i nie ma połączenia z bazą danych, więc to nie zadziała.
Przy tak napisanym kodzie jak powyżej ping zwróci True gdy udało się podniesć połączenie lub poleci exception (dla faFail)
>
>
>
> > Przy debugowaniu doszedłem do function TDataSet.GetNextRecord: Boolean; ale to chyba błędna droga.
>
> > Czy należy poustawiać coś jeszcze?
>
> A masz na pewno ustawione ConentionPooling poprawnie?
oParam := TStringList.Create;
try
oParam.Add('Database=D:\Database\TEST.FDB');
oParam.Add('User_Name=');
oParam.Add('Password=');
oParam.Add('Server=10.0.15.22');
oParam.Add('CharacterSet=WIN1250');
oParam.Add('DriverID=IB');
oParam.Add('SQLDialect=1');
oParam.Add('Pooled=True');
ADManager.AddConnectionDef('BUNIAS', 'IB', oParam);
ADManager.ResourceOptions.AutoReconnect := False;
ADManager.Active := True;
finally
FreeAndNil(oParam);
end;
ADConnection1.ConnectionDefName := 'BUNIAS';
ADConnection1.Connected := True;
>
>
>
>
>
> > Czy ogólnie wznawianie połączenia działa na FireDACu?
>
> Działa porpawnie; sprawdzone na MSSQL, Oracle i Firebrid.
>
>
>
> > Może ktoś podpowie jak to inaczej można zrealizować.
>
> Źle używasz pinga.
>
> Nie jestem pewien czy dobrze ustawiłeś ConnectionPooling.
Zrobiłem taki prosty przykład
procedure TSQLThread.Execute;
var
oQry: TADQuery;
oWait: TWaitResult;
begin
//inherited;
while True do begin
if (Terminated) then
Exit;
oWait := FEvent.WaitFor(1000);
if (oWait = wrSignaled) then begin
FEvent.ResetEvent;
FOnWork := true;
try
try
if (not FDatabase.Ping) then
raise Exception.Create('PING !');
oQry := TADQuery.Create(nil);
oQry.Connection := FDatabase;
oQry.Transaction := FTransaction;
oQry.ResourceOptions.SilentMode := True;
oQry.SQL.Text := 'SELECT current_timestamp from RDB$DATABASE';
oQry.Open();
if (not oQry.Eof) then
FResult := oQry.Fields[0].AsString;
except
on e: Exception do begin
FResult := e.Message;
end;
end;
finally
FOnWork := False;
end;
end;
end;
end;
procedure TSQLThread.prRecoverConnection(ASender: TObject;
const AInitiator: IADStanObject; AException: Exception;
var AAction: TADPhysConnectionRecoverAction);
begin
if (FCount > 1) then begin
AAction := faFail;
Exit;
end;
AAction := faRetry;
Inc(FCount);
end;
Pomińmy proszę kwestę zwracania FResult czy Eventu (TSimpleEvent).
Podłączenie do bazy ustawiam przy tworzeniu wątku. Scenariusz taki.
Mamy włączonego Firebirda. odpalamy event wątku i otrzymujemy aktualny czas.
Zatrzymujemy FB. Odpalamy evnet. Po dwóch próbach w fResult mamy coś takiego
'[FireDAC][Phys][IB]Unable to complete network request to host "10.0.15.22".
Failed to establish a connection.
Nie można nawiązać połączenia, ponieważ komputer docelowy aktywnie go odmawia.
i fajnie bo połącznia nie ma. ale jak widzisz PING przeszedł.
włączamy FB. Ping przechodzi ładnie i dochodzi do oQry.Open(); i wisi.
Wydaje mi się że może to mieć coś wspólnego z transakcja ale w sumie query powinno samo wystartować transakcje.
Pozdrawiam,
Przemek