to może na pocztek trochę o tranakcja, IB i IBXach. IBXy mają taką cechę, że transakcja to osobna kontrolka (nie wiem, czy jeszcze jakieś kontrolki tak mają) więc nie musisz się bawić w rozpoczynanie i kończenie transakcji z poziomu SQLa. Co więcej każde query może mieć właśny komponent IBTransaction, czyli być zamknięte we własną transakcję. Co (jeszcz)więcej każda transakcja może mieć różny poziom izolacji. Nie przeszkadza to oczywiście podpiąć grupy IBQuery pod jedną transakcję. Dodatkowo komponent IBDataBase musi mieć też transaakcję, która jest transakcją domyślną dla kontrolek, którym nie zdefiniujesz wprost innej transakcji.
Teraz z drugiej strony - kiedy są potrzebne transakcje, jak długo powinny trwać, kiedy je otwierać i zamykać.
Z założenia transakcje powinny trwać tyle, ile jest wymagane i ani trochę dłużej. Powodowane jest to tym, że im więcej transakcji i im dłużej są one otwarte tym system ma coraz trudniej (zajmują więcej zasobów, serwer BD też musi gdzieś trzymać dane o wszystkich otwartych transakcjach, zmianach w nich itd). Z tego samego powodu zalecane jest wykonywanie Transaction.Commit (Roolback) zamiast Transaction.CommitRetaining(RollbackRetaining).
A więc jak już wcześniej wspomniałem jedna transakcja musi trwać przez cały czas połączenia z serwerem i ta idealnie się nadaje do wszelkich operacji typu SELECT - selectów nie trzeba zatwierdzać - nic przecież w bazie nie zmieniają (poza SELECT ... FOR UPDATE ale to za chwilę), i serwer też nie musi trymać info o zmianach bo ich nie ma. Domyślną więc zostawiamy dla SELCTów.
Dla zapytań zmieniających dane (INSERT, UPDATE, DELETE) tworzymy oddzielne transakcje. Przy założeniu, że w danym momencie z naszego programu można usunąć/zmodyfikować/dodać tylko JEDEN rekord (okienko modalne) wystarczy nam jedna dodatkowa transakcja (może, a wręcz powinna być na datamodule). Jeśli user może otworzyć sobie do edycji, w tym samym czasie, kilka okienek (co wg mnie jest błędem bo p. Kasia otworzy sobie 20 rekordów do edycji, po czym zawoła ją p. Ania i obie pójdą na 2h na kawę a system wisi) to niestety (albo stety) dla każdego otwartego okienka trzeba mieć osobną transakcję - tu wystarczy IBTransaction umiescić na formatce do edycji/dodania/usunięcia rekordu.
b0bik napisał(a)
Rozumie ze robisz to tak, że pobierasz dane z np TEdit, wstawiasz je jako parametr do Query, SQL lub StoredProc no i Execute ?
dokładnie. Przy małych systemach mam w kodzie INSERT INTO ...(...) VALUES(:p1, :p2, ...); i tyle, przy większych (aże jeden na razie :p) doszedłem do wniosku, że jednak opłaca się posiedzieć nad bazą i napisać Stored Proc, które mi wstawiają dane do bazy (ten system cały czas żyje i często są zmiany i co kiedyś wstawiało się do dwóch tabel teraz jeszcze ląduje w trzeciej itp i prościej mi zmienić SP w bazie niż w aplikacji, kąpilować ją i uaktualniać na wszystkich stanowiskach)
W sumie racja, tylko się zastanawiam jak używanie TQuery wpłynie na bieżącą transakcje, czy polecenie COMMIT mam też wysłać przez Query czy moze użyć metody Commit komponentu TIBTransaction żeby zatwierdzić te zmiany ?
przy IBXach cała procedura wygląda tak (INSERT z kodu delphi):
procedure btnOKClick()
begin
IBTansaction1.StartTransaction; //do niej podpięte jest IBQuery1
with IBQuery1, SQL do
begin
Clear;
Add('INSERT INTO ...(...) VALUES(:p1, :p2, ...)');
ParamByName('p1').AsString := edtxxx.Text;
ParamByName('p2').AsString := edtxxx.Text;
...
try
Execute;
IBTransaction1.Commit;
except
IBTransaction1.Roolback;
end;
end;
end;
Nie miałeś takich problemów ? Czy po wykonaniu zapytania aktualizującego wszystko było widać tak jak trzeba ?
i po wykonaniu tego, jeśli wszystkie transakcje masz na ReadCommited to jak ponownie odczytasz dane to są już widoczne po zmianie
Tylko ja to nie moge obczaić jednej rzeczy. Bo jak używam isql.exe, to jest tak że jak wydam polecenie UPDATE aktualizujące konkretny rekord to od tego momentu on będzie zablokowany dla innych
bo zapewne nie startujesz tam nowej transakcji tylko działasz w domyślnej, a dopóki nie zakończysz (zatwierdzisz lub cofniesz) tej, w której robiłeś UPDATE to dane na dobą sprawe nie są w bazie i rekord ma cały czas status "edytowany". Czyli Zatwierdzenie ub cofnięcie transakcji zapisuje (lub cofa) zmiany i zdejuje znacznik "edytown"z rekordu.
, a jak to jest przy komponentach w Delphi ? Jak wywołam metodę Edit jakiegoś zbioru (TIBTable np) no i sobie wpisuje dane do kontrolek, to czy ten rekord już jest zablokowany dla innych czy dopiero jak wywołam metode Post ? (z tego co próbuje to dopiero po wydaniu metody Post rekord będzie blokowany).
z IBTable nie kożystałem więc ciężko mi powiedzieć
No to tak w skrócie mi powiedz. Masz po prostu kontrolki TEdit czy TComboBox (z wartościami LookUp z innej tabeli) i na podstawie ich zawartości budujesz zapytanie lub parametryzujesz procedure składowaną i odpalasz (Execute) ? W sumie jakbyś napisał jak Ty to robisz to będe wdzięczny.
myślę, że powyższe i ten przykład, który tam jest wystarczą :)
Z tego co widze to zabieram sie do tego od niewłaściwej strony - bo zaczynam teoretyzować a nie spróbowałem jeszcze tego praktykować. Lepiej chyba będzie jak napiszę app, i zacznę ją testować wtedy pewnie część się wyjaśni część się zagatwa : )
co do teoretyzowania to jest to raczej dobra rzecz, bo nie zabieraz się bezwiedzy o temacie, a to potrafi zniechęćć bardzo starannie :). A co do testowania rozwiązań to co sam sprawdzisz to twoje :)
Jeszcze na koniec o edycji, blokowaniu i informowaniu usera, że dany rekord jest już edytowany. (WAŻNE: musisz mieć nowait w transakcji)
Cała procedura wygląda tak
- user naciska Button "Edytuj" (w zmiennej ID masz ID edytowanego rekordu - dla uatwienia :))
- robisz IBTransaction.StartTransaction;
- try
4a. UPDATE edytowana_tablica SET pole_id = pole_id WHERE pole_id = :ID - jes to tzw pusty update, który nie zmienia nic ale ustawia rekord w tryb edycji
4b. lub SELECT * FROM edytowana_tablica WHERE pole_id = :ID FOR UPDATE WITH LOCK
efekt dla obu będzie taki sam
- pokazanie okienka do edycji rekordu, pobranie danych dla comboboxów, wypełnienie editów aktualnymi wartościami rekordu itp
- zrobienie UPDATE
- IBTransaction.Commit
- except
8a. wypadało by sprawdzić czy aby mamy dedlock a nie np. błąd w skłani SQL lub problem z połączeniem
8b. ktoś już edytuje ten rekord - info dla usera
8c. IBTransactio.Roolback
- end (try)
cała "siła" tkwi w pierwszym UPDATE'cie (SELECT'cie), który "sprawdza" czy ktoś przypadkiem nie edytuje już tego rekordu.
PS. jak mi gdzieś zjadło literki lub spc to przez słabe baterie w klawiatórze :)