JPA - metoda flush();

2

Z tego co zrozumiał z dokumentacji metoda flush() wywołana w transakcji ignoruje (obchodzi) jakby transakcje i powoduje przekazanie stanu obiektów encji do bazy danych bez czekania na polecenie commit() dla tej transakcji. Mam pytanie czy to spłukanie "flush'em" to jest już pełne zatwierdzenie zmian w bazie ? Czy jeżeli po flush'u nastąpi rollback transakcji to zmiany dokonane przez flush zostaną cofnięte czy też są już commitowane i pozostaną w bazie?

Z tego co jeszcze wywnioskowałem (a chciałbym potwierdzić) to to że metody detach() i clear() działają również natychmiast pomimo że są wywoływane w transakcji. To znaczy że obiekt encji jest odrywany od Contextu w momencie wywołania tych metod, bez czekania na operację commit() i już nie "manged" w dalszym ciągu transakcji. Czy taka sama natychmiastowa reakcja ignorująca transakcje zachodzi dla wywołań pozostałych metod kaskadowych: merge, remove, refresh?

0

Ja się dołączam do pytania i dodatkowo chciałbym się dowiedzieć czy pod Hibernatem jest tak samo? Tzn przy samodzielnym Hibernacie, a nie jako dostawcy JPA.

1

Załóżmy, że mamy metodę z adnotacją @Transactional (gdy Spring zarządza transakcjami) lub metodę ejb z CMT.

Standardowy flow wygląda następująco.

  1. Na wejściu do metody tworzona jest transakcja.
  2. W trakcie metody są wykonywane różne operacje na encjach. Hibernate może sam zadecydować w trakcie metody, że część zmian trzeba wrzucić do bazy (domyślnie FlushMode jest ustawiony na AUTO, więcej: http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/FlushMode.html)
  3. Na koniec metody wrzucane są pozostałe zmiany.
  4. Transakcja jest commitowana.

Dodanie flush() wymusza wrzucenie zmian do bazy, ale jeszce nie commituje transakcji.
Od tej chwili zmiany są widoczne dla innych transakcji odczytujących dane z poziomem izolacji read uncommitted.
Jeżeli po flush() nastąpi rollback, to wszystkie zmiany zostaną wycofane.

Kiedy przydaje się flush:
-w jednej sesji zmieniamy bardzo dużo obiektów. Aby uniknąć problemów z pamięcią należy w paczkach po np. 200 encji wykonywać zmiany i później wykonywać flush() i następnie clear().
-w jednej sesji najpierw zmieniamy stan w obiekcie, a później w tej samej sesji wywołujemy zapytanie jdbc/procedurę, która korzysta z tych danych. Oczywiście, aby to zapytanie/procedura mogła widzieć dane, muszą one być w bazie. Zapytanie/procedura działa w tej samej transakcji, więc będzie widzieć dane bez potrzeby zmiany poziomu izolacji

Ja się dołączam do pytania i dodatkowo chciałbym się dowiedzieć czy pod Hibernatem jest tak samo? Tzn przy samodzielnym Hibernacie, a nie jako dostawcy JPA.

Nie ma tu znaczenia, czy korzystasz z Session, czy EntityManagera. Obie klasy zachowują się w tym przypadku tak samo.

Z tego co jeszcze wywnioskowałem (a chciałbym potwierdzić) to to że metody detach() i clear() działają również natychmiast pomimo że są wywoływane w transakcji. To znaczy że obiekt encji jest odrywany od Contextu w momencie wywołania tych metod, bez czekania na operację commit() i już nie "manged" w dalszym ciągu transakcji

http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html#clear%28%29:

Completely clear the session. Evict all loaded instances and cancel all pending saves, updates and deletions. Do not close open iterators or instances of ScrollableResults.

Z tego powodu zawsze przed clear() należy wywoływać flush().
W rzeczywistości clear() przydaje się jedynie wtedy, gdy przetwarzamy wiele obiektów w pętli i co pewien czas musimy robić flush(); clear();

1

Generalnie sqlki mogą być trzymane w pamięci podręcznej EM i będą fizycznie wysłane do bazy w momencie zatwierdzania transakcji po stronie JPA. Flush wymusza wysłanie zapamiętanej sqlki/sqlek do bazy, ale nie wysyła commit zatem nawet jak coś się zwali to zawsze można zrobić rollback. Jest oczywiście jedno ale... mianowicie jeżeli wywołasz flush, następnie zrobisz rollback to nie zostaną cofnięte zmiany w sekwencjach, auto-id i tym podobnych duperelach.

0

Dzięki wielkie za wyjaśnienie.

Koziołek

następnie zrobisz rollback to nie zostaną cofnięte zmiany w sekwencjach, auto-id i tym podobnych duperelach.

auto-id - rozumiem że to automatyczne nadawanie numeracji w bazie dla kolejnego rekordu, czyli ten numer po rollbacku się nie wycofa z bazy razem z rekordem. Przy kolejnym dodawaniu kolejne rekordy wejdą do bazy z następnymi numerami i w bazie będzie skok numeracyjny o jedną pozycję czy tak?
Czy może chodzi o pole Primary key (auto-id) czyli numer @GeneratedValue(strategy = GenerationType.AUTO) jaki pobierze sobie obiekt encji przy jego flush'owaniu do bazy i to ten numer w tej encji nie zostanie cofnięty?

Powtórzę jeszcze tylko pytanko o te metody merge, remove, refresh - tez mają taka natychmiastową wykonalność we wnętrzu trwającej transakcji? Czy obiekt encji jest natychmiast mergowany do Conextu albo refreshowany z bazy bez czekania na commit?
Remove podobno oznacza tylko encje do usunięcia a usuwane są dopiero przy commicie.

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