Kilka pytań ze Springa i JPA

0

Cześć :)

Uczę się od kilku dni stacku javowego i mam kilka pytań, na które nie znalazłem do tej pory odpowiedzi. Będę wdzięczny za pomoc :)

repo

  1. Co się dzieje jeśli w bloku @Transactional złapiemy wyjątek w Try i nie zostanie on rozpropagowany? Czy wykona się rollback transakcji?
    Chciałem napisać swoje transakcje i obsłużenie rollbacku w przypadku błędu opakowanego w Either, ale dostaję wyjątek, że "Not allowed to create transaction on shared EntityManager" (można rzucić okiem w repo).

  2. Jak działąją Future'y? Czy jak wywołam get() na CompletableFuture to core CPU zostanie zwolniony i będzie mógł obsłużyć inny request czy muszę zwrócić CompletableFuture z kontrolera, żeby rzeczy wykonały się asynchronicznie.

  3. EntityManager powinien mieć scope Transient czy Request (w dokumentacji Hibernate zalecają Request, ale EMFactory domyślnie chyba zwraca nową instancję przy każdym wywołaniu).
    Chciałem napisać sobie klasę ze scopem Request, które by przyjmowało EMFactory i zwracało ten sam EM, ale leciał wyjątek nawet jak dałem w adnotacji ze scopem proxyMode = ScopedProxyMode.TARGET_CLASS

  4. Follow-up do poprzedniego pytania. Czy 1st lvl cache w JPA jest na poziomie EM czy PersistenceContext (czy jeśli wstrzyknę drugi EM w ramach tego samego PC to czy zmiany, które nie są jeszcze zapisane do DB będą tam widoczne)?

  5. Musiałem dodać @SpringBootApplication(exclude = HibernateJpaAutoConfiguration.class) bo inaczej leciał wyjątek
    "class org.springframework.orm.jpa.EntityManagerHolder cannot be cast to class org.springframework.orm.hibernate5.SessionHolder".
    Gdzie znaleźć info za co odpowiada ta klasa? Google zwraca tylko tutoriale jak to wyłączyć...

Na drugim branchu mam wersję "springową" (ze springową obsługą transakcji). Jakbyście mogli rzucić okiem i podpowiedzieć co lepiej zrobić inaczej :)

6

Ad. 1) Jak zlapiesz wyjatek, to nie bedzie rollbacku, bo aspekt nie zostanie uruchomiony. Nie wiem jak polaczyc adnotacje z Vavrem, zakladam, że to nie jest dobry pomysl - raczej jakis TransactionalTemplate.
Ad. 2) Watek bedzie czekal na wynik obliczenia, nie bedzie obciazal CPU, ale tracisz watek na czas czekania.
Ad. 3) Transakcje i Persistence Context sa podpiete pod watek. W konsekwencji przelaczenie sie na inna pule watkow powoduje utrate kontekstu transakcji i „dzieja sie cuda”, tzn. „nie dziala”. Mozna probowac to obejsc, np. jest wsparcie dla kontekstu Security w tym zakresie.
Ad. 4) W 99% przypadków PC jest na poziomie EM, EM nawet imituje takie API. Jesli chodzi o scope, to jest to jeden watek (wykorzystywany jest pod spodem mechanizm thread local z Javy).
Ad. 5) Tutaj wymiekam, zalecam lekture kodu zrodlowego ;)

4

ad 1)
Zależy - jaki wyjątek i kto go widział. (przy wywoływaniu metod) . W szczególności jeśli wyjątek leci z JPA (np. OptimisticLockException) to transakcja będzie oznaczona jako rollbackOnly od razu i łapanie wyjątku nic już nie da.
Więcej nie chce z pamięci pisać - zasady tego rollbackowania są tak posrane, że cieszę się tylko, że już od jakiegoś czasu nie mam z tym do czynienia.
Rada: Po prostu zapamiętaj, że czasem złapanie wyjątku nic nie da - transakcja i tak pójdzie się dupczyć - jak to się stanie to doczytaj dokumentację konkretnego wyjątku/jpa/springa - to tylko kilka lat lektury - da się znaleźć precyzyjne wyjaśnienie na każdy przypadek.

ad 3)

W 15 przypadkach na 10 używanie scope RequestScope na swoich klasach/polach kończy się wywałką na produkcji.
Najczęściej tylko null pointer exception, ale czasem może np. dojść do mieszania danych klientów.
Nieco ponad rok temu dostałem z jednej firmy takie śledztwo - ktoś zrobił sprytnie wybór bazy danych (multitenancy) poprzez trzymanie EntityManagera (:-)) w Request scope - tylko dzięki constraintom w bazie danych i alertom na logach pomieszało się jakieś kilkadziesiąt rekordów (zanim wyłączono produkcję), a nie pareset tysięcy.
Najgorsze w takich przypadkach jest to, że 9999/10000 transakcji działa poprawnie i nic się nie miesza, a programiści są pewni, że wiedzą jak działa request scope i rozpatrzyli wszystkie przypadki brzegowe - więc to na pewno nie tam jest problem ( ͡° ͜ʖ ͡°)
Rada: nie baw się NIGDY w żadne request scope. Opakuj pola (nawet takie jak EM) we własną normalną klasę (nie beana springowego) i przekazuj jako argument między metodami.

ad 5)
Pytaniem na pytanie:
co właściwie chciałeś uzyskać pisząc ten kod ?
https://github.com/Qbelek/JavaCrud/blob/master/src/main/java/com/example/crud/dbaccess/HibernateConfig.java

Czemu nie pozwoliłeś Springowi samemu stworzyć datasource , sessionfactory itp?

Jak chcesz się bawić gołym JPA to może najlepiej wywal Springa, bo Ci przeszkadza.

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