Thread View: pl.comp.lang.delphi.bazy-danych
7 messages
7 total messages
Started by ufo
Wed, 09 Dec 2015 23:36
Logika pewnej transakcji...
Author: ufo
Date: Wed, 09 Dec 2015 23:36
Date: Wed, 09 Dec 2015 23:36
76 lines
2872 bytes
2872 bytes
Witam, mam problem z cofaniem transakcji w przypadku błędu w następującej sytuacji: - użytkownik używa pewnego formularza do edycji lub dodawania danych (wybiera funkcję Insert lub Edit), jeżeli wybrał Edit, to edytowany rekord jest blokowany (lmPessimistic) i rozpoczyna się transakcja (implikowana przez komponenty UNIDAC), w przypadku Insert nic nie jest blokowane - użytkownik wprowadził dane i naciska OK by je zapisać, wykonuje się kod typu (w dużym uproszczeniu): db.StartTransaction; try Table1.Post; Table2.Post; .... db.Commit; except raise; //błąd - powrót do formularza i ewentualne poprawki end; ... - Jak widać zapisuje się wiele tabel i jeśli wystąpił błąd to raise wraca nas do formularza, gdzie użytkownik może poprawić ew. błędy ( o ile wynikły z błędów wprowadzania). Niestety działa to dobrze tylko w trybie Edit (użytkownik może powtarzać tą procedurę aż do pomyślnego zapisu), w trybie Insert MUSZĘ zakończyć transakcję, ponieważ w tym trybie blokuje ona całą tabelę (w Edit tylko jeden wiersz) dlatego powyższy kod ulega zmianie na: db.StartTransaction; try Table1.Post; Table2.Post; .... db.Commit; except if (EditMode=dsInsert) then //EditMode zmienna określająca tryb edycji begin mdata.db.Commit; //By nie blokwac całej tabeli InsertId:=table1.FieldByName(PrimaryKey).AsInteger; if (InsertId>0) then //zapisał sie głowny rekord begin mdata.db.StartTransaction; //nowa transakcja table1.Edit; //blokada rekordu end; end; end; ... 1. Jak widać z powyższego kodu, gdy nie uda się zapisać pierwszej tabeli (InsertId=0) to wracamy do formularza nic nie robiąc bo table1 jest nadal w trybie dsInsert. 2. Gdy pierwsza i ew. następne tabele się zapisały (InsertId>0) to przełączamy się tryb Edit (table.1Edit), blokując tylko jeden rekord a nie całą tablę i operację można znowu powtarzać aż do skutecznego zapisu. ALE nie podoba mi się to do końca bo: 1. Inni użytkownicy widzą rekord wpisany przy Insert (nie mogą go edytować, bo jest zablokowany) - to da się przeboleć 2. Jeśli użytkownik znudził się próbami zapisu i nacisnął Cancel, to rekordy w tabelach, które udało się zapisać będzie trzeba usunąć (to da się przeboleć), ale może to się też nie udać bo np. zerwało połączenie i wtedy niekompletny zestaw danych będzie gdzieś tam wisiał na zawsze... (to już może być bolesne), co prawda można go jakoś oznaczyć i po pomyślnym zapisie wszystkich table usunąć ta flagę. Czy znacie jakieś bardziej "eleganckie" sposoby przeprowadzenia takiej transakcji?. Przychodzi mi jeszcze do głowy Rollback i table1.Insert ale wtedy użytkownik traci dane w formularzu i trzeba by je jakoś przywracać. Z góry dziękuję Michał
Re: Logika pewnej transakcji...
Author: zpksoft
Date: Thu, 10 Dec 2015 00:50
Date: Thu, 10 Dec 2015 00:50
12 lines
338 bytes
338 bytes
>ciach> Czy znacie jakie¶ bardziej "eleganckie" sposoby przeprowadzenia takiej > transakcji?. Przychodzi mi jeszcze do g³owy Rollback i table1.Insert ale > wtedy u¿ytkownik traci dane w formularzu i trzeba by je jako¶ przywracaæ. > > Z góry dziêkujê > Micha³ sql update zamiast edit w dbgridzie. Pawe³
Re: Logika pewnej transakcji...
Author: szemrany
Date: Thu, 10 Dec 2015 11:51
Date: Thu, 10 Dec 2015 11:51
10 lines
296 bytes
296 bytes
On Thu, 10 Dec 2015 00:50:30 -0800 (PST), zpksoft wrote: > sql update zamiast edit w dbgridzie. A biblioteka dostępowa jak wg Ciebie robi zmiany w bazie? -- howgh szemrany "Trzeba z żywymi naprzód iść, po życie sięgać nowe, a nie w uwiędłych laurów liść z uporem stroić głowę"
Re: Logika pewnej transakcji...
Author: ufo
Date: Thu, 10 Dec 2015 18:03
Date: Thu, 10 Dec 2015 18:03
16 lines
773 bytes
773 bytes
W dniu 2015-12-10 o 11:51, szemrany pisze: > On Thu, 10 Dec 2015 00:50:30 -0800 (PST), zpksoft wrote: > >> sql update zamiast edit w dbgridzie. > > A biblioteka dostępowa jak wg Ciebie robi zmiany w bazie? > Tam w ogóle nie ma grida. Zapisywany obiekt to opis magazynu, kolejne tabele to Magazyn (table1) (zwiera unikalne klucze jak kod i nazwa - tylko tu może powstać błąd zależny od danych wpisanych przez użytkownika), Adres magazynu (table2) i Stany magazynowe (table3) oraz kilka pomniejszych tabel. Ponieważ istnienie każdej z nich bez innej jest bez sensu, to zapisuję to w transakcji. W każdym razie zrobiłem to lepiej, korzystając z CachedUpdates, teraz już da się bez problemu wrócić do formularza i edytować i zapisywać aż do skutku.
Re: Logika pewnej transakcji...
Author: zpksoft
Date: Thu, 10 Dec 2015 23:57
Date: Thu, 10 Dec 2015 23:57
15 lines
377 bytes
377 bytes
W dniu czwartek, 10 grudnia 2015 11:51:54 UTC+1 u¿ytkownik szemrany napisa³: > On Thu, 10 Dec 2015 00:50:30 -0800 (PST), zpksoft wrote: > > > sql update zamiast edit w dbgridzie. > > A biblioteka dostêpowa jak wg Ciebie robi zmiany w bazie? > > -- > howgh > szemrany Nie wiem. Pewnie blokuje rekord na czas edycji. Ale mo¿e to byæ za ma³o. Pawe³
Re: Logika pewnej transakcji...
Author: wloochacz
Date: Fri, 11 Dec 2015 10:50
Date: Fri, 11 Dec 2015 10:50
14 lines
680 bytes
680 bytes
W dniu 2015-12-09 o 23:36, ufo pisze: > Czy znacie jakieś bardziej "eleganckie" sposoby przeprowadzenia takiej > transakcji?. Przychodzi mi jeszcze do głowy Rollback i table1.Insert ale > wtedy użytkownik traci dane w formularzu i trzeba by je jakoś przywracać. Znacie; CachedUpdates, dopóki user nie naciśnie zapisz, nic nie idzie do bazy danych. Przy Insert masz to co chciałeś, ale przy Edit musisz "jakoś" zablokować dokument przed edycją. Pewnie UNIDAC coś tam potrafi zrobić, ale ja używam własnej implmentacji z blokowanie całkowicie zarządzanym przez apliakację (wiem kto, kiedy i z jakiej maszyny zablokował jaki obiekt biznesowy). -- wloochacz
Re: Logika pewnej transakcji...
Author: ufo
Date: Fri, 11 Dec 2015 18:14
Date: Fri, 11 Dec 2015 18:14
70 lines
3074 bytes
3074 bytes
W dniu 2015-12-11 o 10:50, wloochacz pisze: > W dniu 2015-12-09 o 23:36, ufo pisze: >> Czy znacie jakieÅ bardziej "eleganckie" sposoby przeprowadzenia takiej >> transakcji?. Przychodzi mi jeszcze do gÅowy Rollback i table1.Insert ale >> wtedy użytkownik traci dane w formularzu i trzeba by je jakoÅ przywracaÄ. > Znacie; CachedUpdates, dopóki user nie naciÅnie zapisz, nic nie idzie do > bazy danych. > Przy Insert masz to co chciaÅeÅ, ale przy Edit musisz "jakoÅ" zablokowaÄ > dokument przed edycjÄ . > Pewnie UNIDAC coÅ tam potrafi zrobiÄ, ale ja używam wÅasnej implmentacji > z blokowanie caÅkowicie zarzÄ dzanym przez apliakacjÄ (wiem kto, kiedy i > z jakiej maszyny zablokowaÅ jaki obiekt biznesowy). > > No, zapis informacji o blokadzie może byÄ przydatny i tez to później wprowadzÄ. OczywiÅcie można korzystaÄ z blokowania przez db lub z wÅasnego mechanizmu. Można także rozważyÄ lokalnÄ kopiÄ, gdyby komputer użytkownika wywaliÅ siÄ w poÅowie zapisu dużego dokumentu. Unidac z CachedUpdates blokuje rekord w trybie edycji i ustawionym trybie blokady Pessimistic. JeÅli anuluje siÄ transakcjÄ wystarczy uruchomiÄ nowÄ i zablokowaÄ ponownie funkcjÄ Lock. Blokowanie przy użyciu mechanizmów db jest wygodne, może mieÄ jednak uboczne skutki, bo niektóre engine, zamiast pojedynczego rekordu, blokujÄ caÅÄ stronÄ (kilka rekordów). W każdym razie zamieÅciÅem ostatecznÄ wersjÄ na CachedUpdates. Tu każda tabela po pomyÅlnym zapisie, dodaje siÄ do listy. A w razie bÅÄdu jest przywracana do stanu przed zapisem (RestoreUpdates) a caÅoÅc zapisu anulowana przez Rollback. TroszkÄ tu moich "overridowanych" funkcji ale powinno byÄ zrozumiaÅe. if (not mdata.db.InTransaction) then mdata.db.StartTransaction; Tables:=TList.Create; try try Tables.Capacity:; ErrTable:ÚtaQuery; if (DataQuery.State in [dsEdit, dsInsert]) then DataQuery.Post; if (DataQuery.UpdatesPending) then DataQuery.ApplyUpdates; Tables.Add(DataQuery); ErrTable:resFRM.adresQUE; adresFRM.Post(EditMode,15,PrimaryKey,'usr_Key','',false); //to robi post+applyupdates dla tej tabeli Tables.Add(adresFRM.adresQUE); ErrTable:=telfaxFRM.DataQUE; telfaxFRM.ApplyUpdates; Tables.Add(telfaxFRM.DataQUE); ErrTable:=emailFRM.DataQUE; emailFRM.ApplyUpdates; Tables.Add(emailFRM.DataQUE); ErrTable:=komunikatorFRM.DataQUE; komunikatorFRM.ApplyUpdates; Tables.Add(komunikatorFRM.DataQUE); except on E:Exception do begin mdata.db.Rollback; for i := 0 to Tables.Count-1 do TUniQuery(Tables[i]).RestoreUpdates; if EditMode=dsEdit then begin mdata.db.StartTransaction; DataQuery.Lock; end; if (E is EUniError) then mdata.DataBaseError(E as EUniError,Self,ErrTable); raise; end; end; finally Tables.Free; end;
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads