Spring data jpa - modyfikacja encji w innym wątku

0

Nie wiem czy jest sens się rozpisywać ponownie, problem opisałem tutaj:
https://stackoverflow.com/questions/44647782/spring-data-jpa-cache

0

Jak encje zaczytasz to masz w cache L1 i do końca sesji/transakcji stan tego obiektu będzie taki jak w chwili pobrania....i tak jest dobrze. Potrzebujesz izolazcji to rób blokowanie pesymistyczne findWithLock czy coś takiego. Ewentualnie blokowanie optimistyczne i ponawianie

Dodatkowo równie dobrze możesz mieć pretensje o taką sytuacje: pobierasz sobie numer kontrahenta w TX1 i przypisujesz do zmiennej numer w ty czasie ktoś inny poprawia to na bazie a Ty masz pretensje, że zmienna numer dalej posiada starą wartość....

0
Szczery napisał(a):

Jak encje zaczytasz to masz w cache L1 i do końca sesji/transakcji stan tego obiektu będzie taki jak w chwili pobrania....i tak jest dobrze. Potrzebujesz izolazcji to rób blokowanie pesymistyczne findWithLock czy coś takiego. Ewentualnie blokowanie optimistyczne i ponawianie

Dodatkowo równie dobrze możesz mieć pretensje o taką sytuacje: pobierasz sobie numer kontrahenta w TX1 i przypisujesz do zmiennej numer w ty czasie ktoś inny poprawia to na bazie a Ty masz pretensje, że zmienna numer dalej posiada starą wartość....

Problem rozwiązałem wstrzykując entity managera i użyciem metody detach, gdy próbowałem zrobić refresh poleciał wyjątek TransactionRequired (coś w ten deseń) co świadczy o tym, że nie jestem w transakcji, w której pobrałem obiekt za pierwszym razem.
Tylko, że w momencie kiedy czytam drugi raz ten obiekt to robię to w kolejnej transakcji bazodanowej, dlaczego więc cache L1 jeszcze trzyma ten obiekt? Kiedy sesja jest czyszczona? Z tego wynika, że powinno być dobrze (bo obiekt jest pobierany 2 razy ale w 2 różnych transakcjach), czego nie biorę pod uwagę/co źle rozumiem?

1

Dziwi mnie to TransactionRequired. Sprawdź, czy ta druga transakcja łapie, czyli czy da się w niej coś zapisać. Czasem masz @Transactional, ale niedziałający. Wynika to z niewłaściwej konfiguracji springa (transaction manager). Szczególnie jak zaczynasz mieszać z oddzielnym EntityManagerem. To nieładnie pachnie.

2

Ok, już wiemy, że używasz Hibernate, bo najpierw myślałem, że EclipseLink ci keszuje. EclipseLink ma domyślnie włączony query cache, czyli L2. Wg mnie tutaj problemem jest nie transakcja, a sesja jpa. Bo to sesja trzyma w pamięci (L1) pierwotne dane obiektu, dopóki nie zrobi się jej refresha czy czegoś podobnego.

Z [tu jest link:] tego wynika, że powinno być dobrze

Przeczytaj komentarz do tej odpowiedzi: *Well actually that isn't true… * Sesje JPA mogą być powtórnie używane i na pierwszy rzut oka nie wiadomo, czy używasz tej samej sesji czy innej. Najlepiej by było to skonfigurować, ale ciekawe jak.

Entity managera nie wstrzykuj, tylko używaj tego samego, co jpa-data. W punkcie 4.6.2. instrukcji Jpa-Data masz opisane jak uzyskać EntityManagera. No i zrób sobie własną metodę w tym repozytorium - clear czy refresh. Innym poprawnym sposobem uzyskania EM wydaje się być wstrzyknięcie interfejsu JpaContext, też opisane w reference.

Niby inni próbują na siłę wstrzykiwać EM (Spring JpaRepository - Detach and Attach entity), ale jest też komentarz, że nie zadziałało. I ja bym tak nie robił. Te wskazówki są wiarygodne: Explicit use of EntityManager with Spring Data repositories. W skrócie - należy to zaimplementować w środku w Repository.

Nie napisałeś jeszcze o tym, czy Twoja aplikacja to EE czy SE. Bo w EE problem sesji znika, gdyż (domyślnie) w każdym requeście jest nowa sesja jpa, a w ramach tego samego requesta jest ta sama sesja. Czyli dokładnie wiemy, na czym stoimy. Sądząc po problemach, które opisujesz, to używasz SE. No i tu brak wiedzy o tym, czy mamy świeżą sesję jest bolesny. Nie wiem, jak z tym walczyć. Chyba zaimplementowałbym w repository clear i przed każdym użyciem - w którym zależałoby mi na aktualności danych - wykonywał.

0

Ok, już wiemy, że używasz Hibernate, bo najpierw myślałem, że EclipseLink ci keszuje. EclipseLink ma domyślnie włączony query cache, czyli L2. Wg mnie tutaj problemem jest nie transakcja, a sesja jpa. Bo to sesja trzyma w pamięci (L1) pierwotne dane obiektu, dopóki nie zrobi się jej refresha czy czegoś podobnego.

Doszedłem do tych samych wniosków

Przeczytaj komentarz do tej odpowiedzi: Well actually that isn't true… Sesje JPA mogą być powtórnie używane i na pierwszy rzut oka nie wiadomo, czy używasz tej samej sesji czy innej. Najlepiej by było to skonfigurować, ale ciekawe jak.
Nie doczytałem komentarza, dzięki za oświecenie

Innym poprawnym sposobem uzyskania EM wydaje się być wstrzyknięcie interfejsu JpaContext, też opisane w reference.

Dokładnie tak zrobiłem.

Nie napisałeś jeszcze o tym, czy Twoja aplikacja to EE czy SE. Bo w EE problem sesji znika, gdyż (domyślnie) w każdym requeście jest nowa sesja jpa, a w ramach tego samego requesta jest ta sama sesja. Czyli dokładnie wiemy, na czym stoimy. Sądząc po problemach, które opisujesz, to używasz SE. No i tu brak wiedzy o tym, czy mamy świeżą sesję jest bolesny. Nie wiem, jak z tym walczyć. Chyba zaimplementowałbym w repository clear i przed każdym użyciem - w którym zależałoby mi na aktualności danych - wykonywał.

Jak znajdę czas to spróbuję przeanalizować źródła i sprawdzić kiedy dokładnie jest tworzona nowa sesja, ale wygląda na to, że dla javy SE najlepszym rozwiązaniem byłoby nadpisanie wszystkich metod "find" i dodanie czyszczenia cache przed wywołaniem? To jest głupie.

Dam znać jak coś znajdę, dzięki za pomoc!

0

Chyba mam, powiedz mi jeszcze tylko w związku z tym:

Nie napisałeś jeszcze o tym, czy Twoja aplikacja to EE czy SE. Bo w EE problem sesji znika, gdyż (domyślnie) w każdym requeście jest nowa sesja jpa, a w ramach tego samego requesta jest ta sama sesja.

Masz tu na myśli po prostu zwykły request (np kopnięcie mojego restcontrollera)?

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