Ustawienia FireDAC - transakcje

0

Cześć, od pewnego czasu używam Firedaca w delphi i bardzo mi się podoba.
Chciałbym zapytać kogoś bardziej obeznanego ode mnie, jakie opcje w nim ustawić aby jak najlepiej i najbezpieczeniej działać w środowisku sieciowym, gdzie:

  1. Baza danych to MSSQL.
  2. Stoi centralnie w sieci lokalnej, a aplikacje klienckie - około 50 stanowisk łączą się do bazy bezpośrednio.
  3. Obsługuję transakcje na operacje INSERT, UPDATE oraz DELETE (na SELECT nie stosuję, zresztą prawdopodobnie MSSQL nie obsługiwałby ich dobrze, bo mam zagnieżdżone zapytania).
  4. Sterowniki ODBC 11 SQLI są na każdym stanowisku.

Zależy mi aby nie było żadnych zakleszczeń itp itd żeby było jak najbezpieczniej i nic się nie wieszało.

pozdrawiam
Bartek

2
swiezak111 napisał(a):

Zależy mi aby nie było żadnych zakleszczeń itp itd żeby było jak najbezpieczniej i nic się nie wieszało.

pozdrawiam
Bartek

Żeby nie było zakleszczeń nie wystarczy magiczne ustawienie transakcji. Trzeba odpowiednio napisać cały program (w szczególności mam na myśli zarządzanie transakcjami). Niestety muszę Cię zmartwić, ale Delphi samo z siebie promuje złe pisanie aplikacji (w szczególności bazodanowych). Mając taki edytor wizualny aż się prosi aby walnąć komponenty na formatce: Database, Transaction, Query, Update połączyć to wszystko z kontrolkami bazodanowymi za pomocą DataSeta i gotowe. A to najszybsza droga do powstawania zakleszczeń. Co więcej zaleca się aby transakcje były najkrótsze jak to tylko możliwe. A taka architektura całkowicie temu przeczy.

Najlepiej jest otwierać transakcję na krótko przed zapisaniem danych do bazy, zapisać dane, następnie dać Commit i tak za każdym razem. Co więcej można mieć parę transakcji jedna tylko do odczytu po to aby pobierać dane, a zapisywać dane możesz za pomocą kolejnych krótko trwających. Mogę Ci polecić ten dokument na początek https://firebirdsql.org/file/documentation/reference_manuals/fbdevgd-en/Firebird_Devel_Guide_30EN.pdf Co prawda bazuje od na serwerze Firebird, ale generalne zasady będą podobne. Jest w nim umieszczony rozdział poświęcony Firedac'owi pod Delphi. Są tam naświetlone szerzej sprawy które tu poruszyłem.

0

AKurat firebird obsluguje z tego co wiem transakcje zagniezdzone, wiec jest niby 'latwiej' nie mniej jednak dzięki za info.
PS. Nie klepię formatek i nie kładę komponentów FD na nich.

0
Mr.YaHooo napisał(a):
swiezak111 napisał(a):

Zależy mi aby nie było żadnych zakleszczeń itp itd żeby było jak najbezpieczniej i nic się nie wieszało.

pozdrawiam
Bartek

Żeby nie było zakleszczeń nie wystarczy magiczne ustawienie transakcji.

Trochę jednak wystarczy - SNAPSHOT Isolation Level się kłania...
Ale zostawmy to, ponieważ o zakleszczeniach można co najmniej doktorat napisać i temat nie zostanie wyczerpany.
Od tego czy one się pojawią, czy nie, to bardzo dużo zależy...
Co ciekawe, poprawne używanie transakcji wcale nie musi chronić przed zakleszczeniami.

Trzeba odpowiednio napisać cały program (w szczególności mam na myśli zarządzanie transakcjami).

Własnie chodzi o to, że nie tylko transakcje. Sama konstrukcja kodu SQL, kolejność dostępu do zasobów (tabel, widoków) dla SELECT i UPDATE może mieć wpływ na powstawanie zakleszczeń.

Niestety muszę Cię zmartwić, ale Delphi samo z siebie promuje złe pisanie aplikacji (w szczególności bazodanowych). Mając taki edytor wizualny aż się prosi aby walnąć komponenty na formatce: Database, Transaction, Query, Update połączyć to wszystko z kontrolkami bazodanowymi za pomocą DataSeta i gotowe. A to najszybsza droga do powstawania zakleszczeń.

No i gdzie tu jest potencjał na zakleszcenia?
Ja go jeszcze nie widzę.
To czy dany SQL zostanie wygenerowany przez komponenty, czy z kodu nie ma przecież żadnego znaczenia.

Co więcej zaleca się aby transakcje były najkrótsze jak to tylko możliwe. A taka architektura całkowicie temu przeczy.

Tak, a niby dlaczego przeczy?
Mam wrażanie, że tak naprawdę i dokładnie nie wiesz jak działa zarządzanie transakcjami w trybie auto w FireDAC.
To co napisałeś powyżej, wcale, ale to wcale nie oznacza, ze będą tam gdziekolwiek długie transakcje.
Wręcz przeciwnie.

Najlepiej jest otwierać transakcję na krótko przed zapisaniem danych do bazy, zapisać dane, następnie dać Commit i tak za każdym razem. Co więcej można mieć parę transakcji jedna tylko do odczytu po to aby pobierać dane, a zapisywać dane możesz za pomocą kolejnych krótko trwających. Mogę Ci polecić ten dokument na początek

Jednak nie wiesz o czym piszesz...

https://firebirdsql.org/file/documentation/reference_manuals/fbdevgd-en/Firebird_Devel_Guide_30EN.pdf Co prawda bazuje od na serwerze Firebird, ale generalne zasady będą podobne.

I tu jest właśnie pies pogrzebany.
Takie rzeczy, czyli wiele równoczesnych transakcji na jednym połączeniu (Connection) to na pewno nie w MSSQL, ale na pewno w Firebird.

Jest w nim umieszczony rozdział poświęcony Firedac'owi pod Delphi. Są tam naświetlone szerzej sprawy które tu poruszyłem.

Które na nic mu się nie przydadzą, ponieważ nie pracuje z Firebird.

1
swiezak111 napisał(a):

Cześć, od pewnego czasu używam Firedaca w delphi i bardzo mi się podoba.
Chciałbym zapytać kogoś bardziej obeznanego ode mnie, jakie opcje w nim ustawić aby jak najlepiej i najbezpieczeniej działać w środowisku sieciowym, gdzie:

Nie da się ustawić FireDAC tak, aby zakleszczeń nie było w ogóle. Zwłaszcza, że przyczyna zakleszczeń nie leży tylko i wyłącznie po stronie biblioteki dostępu do bazy danych, takiej jak FireDAC...
Aby ich nie było, trzeba dysponować dogłębną wiedzą skąd one się w ogóle biorą i co może być ich przyczyną w MSSQL.
To ważne - MSSQL, to MSSQL.
Inna baza - inne zasady.

Oczywiście są ogólne zalecenia, @Mr.YaHooo o jednej napisał - transakcje powinny być jak najkrótsze.
Ale to wcale nie znaczy, ze uchroni nas to przed zakleszczeniami...

  1. Baza danych to MSSQL.
  2. Stoi centralnie w sieci lokalnej, a aplikacje klienckie - około 50 stanowisk łączą się do bazy bezpośrednio.
  3. Obsługuję transakcje na operacje INSERT, UPDATE oraz DELETE (na SELECT nie stosuję, zresztą prawdopodobnie MSSQL nie obsługiwałby ich dobrze, bo mam zagnieżdżone zapytania).

Wszystko, również SELECT, jest wykonywane w kontekście transakcji.
Jeśli nie wystartujesz jej jawnie, to zostanie ona wystartowana niejawnie.
To, że jej nie startujesz dla SELECT, nie oznacza że jej tam nie ma.

No i co to znaczy: zresztą prawdopodobnie MSSQL nie obsługiwałby ich dobrze, bo mam zagnieżdżone zapytania?
Zagnieżdżone zapytania to nie zagnieżdżone transakcje, ani wiele równoczesnych transakcji.
W ogóle nie rozumiem, co tu jest napisane...

Ale tak - MSSQL obsługuje zagnieżdżone transakcje i zapytania.

  1. Sterowniki ODBC 11 SQLI są na każdym stanowisku.

Chodzi o SQL Server Native Client for ODBC?
Tak, to podstawa.

Zależy mi aby nie było żadnych zakleszczeń itp itd żeby było jak najbezpieczniej i nic się nie wieszało.

Ha, ha - no to dobre jest :)
Naprawdę nie wiem jak Ci odpowiedzieć.
No, może gdybyś zadał konkretne pytanie...

0
wloochacz napisał(a):

Ale zostawmy to, ponieważ o zakleszczeniach można co najmniej doktorat napisać i temat nie zostanie wyczerpany.

Niestety, dlatego wiem, że sam jeszcze dużo nie wiem... ;)

wloochacz napisał(a):

Od tego czy one się pojawią, czy nie, to bardzo dużo zależy...
Co ciekawe, poprawne używanie transakcji wcale nie musi chronić przed zakleszczeniami.

Oczywiście nawet bardzo dobrze napisany program trzeba zabezpieczyć przed wystąpieniem zakleszczeń i tyle.

wloochacz napisał(a):

Własnie chodzi o to, że nie tylko transakcje. Sama konstrukcja kodu SQL, kolejność dostępu do zasobów (tabel, widoków) dla SELECT i UPDATE może mieć wpływ na powstawanie zakleszczeń.

Faktycznie. U mnie jest o tyle dobrze, że całość jest ogólnie prosta (od strony SQL'a), a mimo to jakiś czas temu zmagaliśmy się z zakleszczeniami spowodowanymi po prostu błędnie napisanym modułem.

wloochacz napisał(a):

No i gdzie tu jest potencjał na zakleszcenia?
Ja go jeszcze nie widzę.
To czy dany SQL zostanie wygenerowany przez komponenty, czy z kodu nie ma przecież żadnego znaczenia.

Oczywiście, że to nie jest wina SQL'a. Jednak takie klepanie komponentów na formatce oraz używanie jednej transakcji dla wszystkiego u nas spowodowało, że przy wystąpieniu niektórych wyjątków program po prostu nie dawał commita... Stąd mój uraz do takiej architektury.

wloochacz napisał(a):

Tak, a niby dlaczego przeczy?

Właśnie z powodów opisanych wyżej. Tak wiem, że to wina słabego kodu (my piszemy w C++ i z analogicznych powodów w C++ istnieją wycieki pamięci). Jak mamy dla każdej operacji tworzoną nową transakcję która jest zwalniana oraz zatwierdzana automatycznie podczas niszczenia obiektu eliminujemy takie zagubione transakcje.

wloochacz napisał(a):

Mam wrażanie, że tak naprawdę i dokładnie nie wiesz jak działa zarządzanie transakcjami w trybie auto w FireDAC.
To co napisałeś powyżej, wcale, ale to wcale nie oznacza, ze będą tam gdziekolwiek długie transakcje.
Wręcz przeciwnie.

Fakt, nie używamy FireDAC'a. Więc może tu jest po prostu inaczej i cały mój post można wywalić w kosmos ;)

wloochacz napisał(a):

Które na nic mu się nie przydadzą, ponieważ nie pracuje z Firebird.

Ok, ale jednak da jakieś ogólne pojęcie jak używać FireDAC'a, bo nie wiemy na jakim poziomie jest pytacz.

0

dzięki Panowie,
to może zadam konkretne pytania, kto ma ochotę może się podzielić wiedzą:

Póki co mam jedno CONNECTION na całą aplikację - taki singleton,
Co prawda mam ConnectionManagera, ale w sumie używam jednego połączenia (w jednym miejscu dwóch na przemian, ale to wyjątek).
Zagnieżdzone zapytania oczywiście używam, zagnieżdzonych transakcji nie, bo pierwsze testy pokazały że baza 'wisiała', coś zrobiłem nie tak stąd założyłem temat (i skasowałem zagnieżdzone transakcje w dwóch miejsach).
Czy dobrze jest używać jednego Connection cały czas?
Jeśli tak to trzymać go cały czas otwartego czy otwierać przed 'kwerendami'.? A jeśli nie to jak to robić?

1
swiezak111 napisał(a):

dzięki Panowie,
to może zadam konkretne pytania, kto ma ochotę może się podzielić wiedzą:

Póki co mam jedno CONNECTION na całą aplikację - taki singleton,
Co prawda mam ConnectionManagera, ale w sumie używam jednego połączenia (w jednym miejscu dwóch na przemian, ale to wyjątek).

Co to za ConnectionManager i jeśli nie jest to FDManager, to dlaczego nie jest?
FDManager: http://docwiki.embarcadero.com/Libraries/Tokyo/en/FireDAC.Comp.Client.TFDManager

Zagnieżdzone zapytania oczywiście używam, zagnieżdzonych transakcji nie, bo pierwsze testy pokazały że baza 'wisiała', coś zrobiłem nie tak stąd założyłem temat (i skasowałem zagnieżdzone transakcje w dwóch miejsach).
Czy dobrze jest używać jednego Connection cały czas?

To zależy.
Musisz pamiętać (dla MSSQL), że każde nowa transakcja może być wystartowana tylko w kontekście konkretnego Connection.
Nie da się wystartować dwóch równoległych transakcji (z tego co wiem, to jest możliwe tylko dla baz danych FB/IB) w jednym Connection, poza transakcjami zagnieżdżonymi.
Tu więcej o transakcjach:
Managing Transactions (FireDAC)

Jeśli chcesz pracować z bazą danych w wątku, to uznaj że musisz mieć osobne połączenie na każdy wątek.

Jeśli tak to trzymać go cały czas otwartego czy otwierać przed 'kwerendami'.? A jeśli nie to jak to robić?

Rozważ zastosowanie Connection pooling
W przypadku MSSQL jest jeszcze kilka innych myków - np. jeśli nie będziesz pobierał na klienta pełnego zestawu danych, a będziesz pracował ze współdzielonym Connection na wiele zapytań, to musisz włączyć MARSa.
Tu więcej o definicji połączenia dla MSSQL w FireDAC
Nie jest problemem trzymanie otwartego połączenia (zwłaszcza, że FireDAC bardzo dobrze sobie radzi z recovering connection), ale problem może być trzymanie otwartego kursora po stronie bazy danych.
Tak się dzieje się wtedy, kiedy pobierasz dane z serwera paczkami (czyli tzw. fetch on demand).
Tu więcej o trybach pobierania danych w FireDAC

I teraz tak; dalej nie mam pojęcia co Ci radzić, bo zadałeś jedno pytanie, na które nie ma prostej odpowiedzi.
Wszystko zależy co chcesz robić, co to za aplikacja, jakie ma obciążanie, jaką ma dynamikę zmian, itd.

Jeśli możesz (ponieważ nie masz dużo danych lub pracujesz z danymi, które są posegmentowane i w efekcie zbyt wiele nie leci na klienta), to najbezpieczniejszym i najszybszym rozwiązaniem będzie tzw. praca w trybie FetchAll.
Tylko, ze to pobiera wszystkie dane na klienta z zapytania w momencie jego otwarcia. A to nie zawsze jest pożądane zachowanie...

0

Dzięki @wloochacz.
Oczywiscie chodzilo mi o FDManagera.

MARSa używam.

Do reszty spraw się odniosę niebawem, bo na szybko odpisuję.

0

Panie @wloochacz,
załóżmy że robię procedurę, którą opakowałem transakcją.

1. start transakcji
2. procedura
3. koniec transakcji

i teraz ciało procedury:

1. usuń coś z tabeli 1
2. Pobierz selectem ID
3. Przetwórz IDki
4. usuń coś z tabeli tabeli2
3. koniec transakcji

Z tego co napisałeś, że nawet SELECT może być opakowany samoczynnie transakcją, to w tym wypadku mam zagnieżdzenia niestety (na jednym Connection)...

0
swiezak111 napisał(a):

Panie @wloochacz,

Tu jest pełna konsultingowa, co prawda nie moja, ale może by się Wam/Tobie przydała :)

załóżmy że robię procedurę, którą opakowałem transakcją.

1. start transakcji
2. procedura
3. koniec transakcji

i teraz ciało procedury:

1. usuń coś z tabeli 1
2. Pobierz selectem ID
3. Przetwórz IDki
4. usuń coś z tabeli tabeli2
3. koniec transakcji

Z tego co napisałeś, że nawet SELECT może być opakowany samoczynnie transakcją, to w tym wypadku mam zagnieżdzenia niestety (na jednym Connection)...

Niezupełnie; musisz pamiętać o tym, że ta zasada dotyczy transakcji jawnie wystartowanych przez Ciebie na poziomie konkretnej instancji TFDConnection.
To że masz SELECT na tym Connection i otwarte kursory, nie oznacza, że nie będziesz mógł zrobić StartTransaction.
Sam sprawdź :)

Zagnieżdżanie będzie wtedy:

fdConnection.StartTransaction;
  coś tam...
  fdConnection.StartTransaction;
  Coś innego...
  fdConnection.Commit;
fdConnection.Commit;

No nawet jeśli, to dlaczego niestety?

0

Staram się takich jawnych zagnieżdżonych tansakcji nie mieć. Czy się jakieś inne samoczynnie tworzą np. przy selecie to nie wiem...

0
swiezak111 napisał(a):

Staram się takich jawnych zagnieżdżonych tansakcji nie mieć.

Osobiście używam, kiedy jest to niezbędne.
Nie ma z tym żadnych problemów, po prostu jak ze wszystkim - trzeba rozumieć jak to działa.

Czy się jakieś inne samoczynnie tworzą np. przy selecie to nie wiem...

Są, bo taka specyfika MSSQLa, ale nie zobaczysz ich na poziomie FDConnection.
Innymi słowy; jeśli zrobisz query.Open, to na poziomie fdConnection.InTrasaction będzie False.
Czyli transakcji nie ma.
Będzie, jeśli jawnie wykonasz fdConnection.StartTransaction.
A z punktu widzenia bazy danych, to transakcja jest zakładana na odczyt danych i ona może blokować inne operacje, ale tu oczywiście tu też zależy od np. poziomu izolacji transakcji, jaką ustawisz przy połączeniu z serwerem.

0
wloochacz napisał(a):

Będzie, jeśli jawnie wykonasz fdConnection.StartTransaction.
A z punktu widzenia bazy danych, to transakcja jest zakładana na odczyt danych i ona może blokować inne operacje, ale tu oczywiście tu też zależy od np. poziomu izolacji transakcji, jaką ustawisz przy połączeniu z serwerem.

Dzięki @wloochacz, a czy możesz mi doradzić jaki poziom izolacji ustawić dla MSSQL w Firedacu? Jaki Ty ustawiasz najczęściej lub jaki jest może mniej restrykcyjny, a jednocześnie który nie będzie sprawiał problemów?

0

Dzięki @wloochacz, a czy możesz mi doradzić jaki poziom izolacji ustawić dla MSSQL w Firedacu? Jaki Ty ustawiasz najczęściej lub jaki jest może mniej restrykcyjny, a jednocześnie który nie będzie sprawiał problemów?

Nie ma tak dobrze, że ustawimy właściwość i będzie "mniej restrykcyjny, a jednocześnie który nie będzie sprawiał problemów".
To, jestem pewien że już o tym pisałem, zależy.
Ja pracuję z READ_COMMITTED_SNAPSHOT, ale tylko dlatego, że mam dość specyficzne wymagania.

1 użytkowników online, w tym zalogowanych: 0, gości: 1