Spring błędy

Najczęściej popełniane błędy w Spring Framework

Spring to obecnie najpopularniejszy framework w świecie Javy. Pozostawia on daleko w tyle całą konkurencję. Dlatego jego dobra znajomość, to podstawa pracy każdego developera. W tym artykule opisuję najczęściej popełniane błędy dotyczące tego frameworka.

Nieodpowiednie używanie transakcji

Brak @Transactional

Transakcje to jedna z najważniejszych rzeczy w aplikacji (jeśli oczywiście używacie transakcyjnej bazy danych). Każde zapytanie odbywa się w jakiejś transakcji. Jeśli zapomnisz dodać adnotację @Transactional na odpowiednich metodach, to każde zapytanie wykona się w osobnej transakcji, co może prowadzić do niespójności danych. W większości przypadków, w prostych aplikacjach nie ma z tym problemu, ale często dzieję się tak, że zapisywane są całe grupy obiektów, które odpowiadają rekordom w różnych tabelach, wtedy o wiele łatwiej doprowadzić do niespójności danych.

Niezrozumienie mechanizmu transakcji

Kolejnym problemem związanym z transakcjami jest niezrozumienie tego, jak one działają w springu. Spring używa AOP (Aspect Oriented Programming) do mechanizmu transakcji. To znaczy, że kod, który piszesz jest dodatkowo opakowywany kodem aspektu, który dodaje obsługę transakcji. Aspekt transakcyjny działa tylko na publicznych metodach klas, więc adnotacja @Transactional nie daje żadnego efektu na metodach prywatnych.

Kolejną istotną kwestią jest wywoływanie metod w obrębie jednego serwisu. Wywołanie metody publicznej oznaczonej adnotacją @Transactional w innej metodzie tego serwisu, też nie da żadnego efektu. Inaczej mówiąc: wywołanie metody transakcyjnej musi pochodzić z zewnątrz serwisu (lub innego beana).

Niepotrzebnie ustawione parametry propagation

@Transactional(propagation = Propagation.REQUIRED)  – często spotkałem się z niepotrzebnym ustawianiem parametru propagation np. Propagation.REQUIRED – jest to opcja domyślna i nie jest wymagana – lub ustawianie Propagation.REQUIRES_NEW tam, gdzie nie była potrzeba nowa transakcja. Warto zapoznać się ze wszystkimi poziomami propagacji transakcji przed ich użyciem. Jeśli nie masz pewności co jak działa, zapytaj kogoś, czy dobrze rozumiesz te rzeczy.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html#REQUIRED

Używanie transakcji wraz z nietransakcyjnym api

Jeśli musisz łączyć transakcyjne operacje z nietransakcyjnymi, to należy umieści je w odpowiedniej kolejności. Najpierw wywołujemy transakcyjne operacje, wtedy w wypadku błędu transakcja zostanie z rollbackowana. Na koniec wywołujemy nietransakcyjne operacje. W wypadku błędu tej operacji, też transakcja zostanie z rollbakowana. Jeśli wszystko pójdzie dobrze, transakcja zostanie zacommitowana. Gdy umieścimy operacje w odwrotnej kolejności, nietransakcyjna operacja może zakończyć się powodzeniem (np. jakaś akcja w zewnętrznym systemie zostanie wykonana), a operacje na bazie danych mogą spowodować błąd i transakcja zostanie cofnięta, ale operacji nietransakcyjnej nie da się już cofnąć.

Transakcje ReadOnly

Adnotacja @Transactional posiada parametr readOnly. Przy odpowiednim ustawieniu @Transactional(readOnly = true) transakcja powinna być tylko do odczytu. Jednak nie jest to prawda. Jest to tylko podpowiedź dla programisty (i systemu transakcji), że ta transakcja powinna tylko odczytywać dane. Jak zauważył w komentarzach RSWRC w Springu 5.1 zostało to poprawione. Dzięki czemu możemy w ten sposób zaoszczędzić trochę pamięci i czasu procesora. Więcej informacji na githubie #21494.

Niezrozumienie parametrów noRollbackFor i rollbackFor

Domyślnie transakcje są rollbackowane tylko dla UncheckedException, można to zachowanie zmienić poprzez użycie parametrów noRollbackFor i rollbackFor. noRollbackFor pozwala podać wyjątek (uchecked), który nie z rollbackuje transakcji. Natomiast rollbackFor pozwala podać, który wyjątek (checked) spowoduje rollback transakcji.

 

Niepotrzebne użycie adnotacji @Autowired

Adnotacja @Autowired służy do wstrzykiwania zależności, ale spring daje kila możliwości na robienie tego. Pierwsza: wstrzykiwanie poprzez pola, druga poprzez konstruktory. O ile w przypadku pól adnotacja ta jest wymagana, to od Springa 4.3 adnotacja ta nie jest wymagana na konstruktorze. Wstrzykując przez konstruktor nie musisz jej w ogóle używać.

Wstrzykiwanie zależności przez konstruktor jest najbardziej naturalnym sposobem ich wstrzykiwania. Dzięki takiemu podejściu, w łatwy sposób możesz później używać beanów springowych w testach. Pozwala to zmniejszyć uzależnienie się od specyfiki frameworka.

 

Brak adnotacji @Valid

Jeśli korzystamy z mechanizmu Bean Validation do sprawdzania poprawności danych wejściowych, konieczne jest umieszczenie adnotacji @Valid na parametrze metody kontrolera. Inaczej mechanizm walidacji nie zostanie uruchomiony. Wielu programistów często o tym zapomina.

@PostMapping
public ResponseEntity<Long> createPerson(@RequestBody @Valid PersonDto personDto) {
  //...
}

 

Niepotrzebne Użycie „implements Serializable”

Często wielu programistów dodaje implements Serializable do obiektów, które zwracają w REST API (zwracających jsona). Nie jest to potrzebne. Jackson (domyślna biblioteka serializująca obiekty do jsona w springu) nie wymaga tego. Serializable jest wymagana tylko wtedy, gdy w kontenerze serwletów, korzystasz z sesji http i zapisujesz w niej obiekty.

 

Podsumowanie

Opisałem najczęstsze błędy, z jakimi się spotykam podczas pracy. Jeśli znasz jeszcze jakieś ciekawe i często powtarzające się błędy, to zachęcam do podzielenia się nimi w komentarzach 😉

 

Źródła:

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html#REQUIRED

https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/data-access.html#transaction

 

Mateusz Dąbrowski

Cześć jestem Mateusz, zajmuję się programowaniem już ponad 12 lat z czego ponad 8 programuję w Javie. Zapraszam Cię do lektury mojego bloga. Możesz przeczytać więcej o mnie >>TUTAJ<<

7 thoughts to “Najczęściej popełniane błędy w Spring Framework”

    1. Dzięki za komentarz. Dobrze wiedzieć, że zostało to poprawione 😉 Poprawię w artykule.

  1. Krótko i w sedno, bardzo trafny artykuł. Ze swojej strony bardzo często spotykam też wrzucanie do kontekstu Springowego wszystkich obiektów jak popadnie w klasach konfiguracyjnych.

    1. Dzięki za komentarz Paweł. Zastanawiałem się, czy dodać to w artykule, ale trochę trudno jest określić co można a czego nie powinno się dodawać do kontekstu, to zawsze jest kwestia indywidualna, dlatego tego nie ma.

  2. Ciekawy artykuł. Chętnie będę czytał kolejne tego typu ciekawostki lub uwagi 🙂

  3. Cześć,

    Mała uwaga redakcyjna: zamień „nie zrozumienie” na niezrozumienie.

Komentarze są zamknięte.