Java Developer? Przejdź na wyższy poziom wiedzy 🔥💪  Sprawdź

Team Leader? Podnieś efektywność swojego zespołu 👌 Sprawdź

Anotacje w Hibernate, które warto znać 💡

utworzone przez Hibernate, Java

Cześć! Witaj w kolejnym wpisie z Hibernate.

Zanim jednak do tego przejdę… W naszym newsletterze w ostatniej wiadomości prosiłem naszą małą społeczność o udział w ankiecie na temat Programu Java Developera. Odzew był MEGA 💪. Zaskoczyło nas to, jak dobrze został przyjęty! Dzięki!

Dopinamy ostatnie kwestie techniczne, rendery materiałów, wprowadzamy poprawki po review i za kilka tygodni oddamy w Twoje ręce Program Java Developera 🚀

12 modułów udostępnianych tydzień po tygodniu, 40 godzin lekcji video, sporo fajnych technologii i DOŻYWOTNI dostęp do materiałów.

Do rzeczy, co z tymi anotacjami!

Wstęp

Korzystając z Hibernate czy też Java Persistence API dla konfiguracji mapowania danych i operacji przeważnie korzysta się z anotacji (jest także możliwość konfiguracji poprzez pliki XML). Korzystasz z @Entity, @Id dla definicji encji i ewentualnie odpowiedników @Table i @Column dla wskazania miejsca w bazie danych dla tych danych.

Idąc dalej, skorzystasz z auto-generacji identyfikatorów @GeneratedValue, mapowania danych z wykorzystaniem @Convert, @Lob, @Enumerated czy @Temporal. Możesz zdefiniować relacje, użyjesz @Query/@NamedQuery czy @NativeQuery dla definicji zapytań.

Ale zarówno Hibernate jak i JPA dostarczają wielu dodatkowych anotacji, z których chciałbym Ci przedstawić kilka wybranych.

Eeee tam, znowu hibernate i podstawy…

Ale może Cię zaskoczę 🙂 Przeczytaj dalej i daj znać w komentarzu, czy znasz te anotacje i czy używałeś ich w projekcie!

We wpisie przeczytasz o

  • @DynamicUpdate – bardziej sprytne generowanie zapytań
  • @Immutable
  • @Transient
  • @Formula – i tu można coś bardzo optymalizować, jeżeli to koniecznie
  • Automatyczna data utworzenia i modyfikacji: @CreationTimestamp oraz @UpdateTimestamp

Wydajność Hibernate

Twórz szybko działające aplikacje z wydajną i zoptymalizowaną obsługą bazy danych.

@DynamicUpdate

Anotacja DynamicUpdate pakietu org.hibernate.annotations włącza inteligentny tryb wykrywania zmian. Zapytania generowane przez Hibernate, reprezentujące instrukcję UPDATE będą zawierały tylko kolumny, które się zmieniły dla encji, dla której anotacja została dodana.

Istnieje również anotacja @DynamicInsert. Dla tej anotacji instrukcje INSERT będą zawierały tylko kolumny, których wartość jest różna od null.

Poniżej masz przykład kodu

@Entity
@DynamicUpdate
public class Card {

    @Id
    String cardId;

    @Convert(converter = YesNoBooleanConverter.class)
    Boolean enabled;

    @Enumerated(EnumType.STRING)
    CardCountry cardCountry;

    BigDecimal balance;

    @Temporal(TemporalType.DATE)
    Calendar expiresAt;
}

Jeżeli np. zmodyfikujesz wartość balance, to wygenerowane zapytanie SQL będzie wyglądało następująco

update
        cards 
    set
        balance=?,
        country=?,
        enabled=?,
        expires_at=?
    where
        card_id=?

Po dodaniu @DynamicUpdate wygenerowane zapytanie będzie zawierało tylko zmienioną kolumnę

update
        cards 
    set
        balance=?
    where
        card_id=?

@Immutable

Anotacja Immutable pakietu org.hibernate.annotations włącza mechanizm, który nie pozwala na zmianę danych encji. Takie encje można dodawać i usuwać, ale nie można ich modyfikować. Nawet jeżeli zmienisz wartość pola w tej encji, to Hibernate zignoruje te zmiany i instrukcja UPDATE nie zostanie wysłana.

Anotacja może także być umieszczona nad polem, wówczas zasięg ograniczony jest do pól oznaczonych tą encją.

Psst… Interesujący artykuł?

Jeżeli podoba Ci się ten artykuł i chcesz takich więcej – dołącz do newslettera. Nie ominą Cię materiały tego typu.

.

@Transient

Jest to anotacja JPA i jest dostępna w pakiecie javax.persistence. Można ją ustawić dla pola, przez co pole jest oznaczone jako nie persystentne. Hibernate nie obsługuje takich pól (nie będzie ich szukał ani aktualizował). Może to być wykorzystane do chwilowego wtłoczenia dodatkowych danych czy na przykład wstawienia daty odczytu encji z bazy danych.

Uwaga. Należy ostrożnie podchodzić do tego typu pól – np. co się ma stać z takim polem i encją po EntityManager.refresh czy też po commit (data odczytu może już nie mieć sensu).

@Formula

Anotacja znajduje się w pakiecie javax.persistence i pozwala na dodanie pola, do którego zostanie wstrzyknięty wynik natywnego zapytania SQL. Pole takie jest polem tylko do odczytu.

Przykładowo chciałbyś wyświetlić listę użytkowników z informacją o liczbie kart. Poniżej masz przykład kodu z relacją OneToMany

@Entity
public class User {
    @Id
    String userId;

    String firstName;

    String lastName;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name = "CARD_OWNER_ID")
    List<Card> userCards;    
}

Wywołując zapytanie HQL/JPQL będzie musiał uważać na problem N=1 i użyć np. left join fetch.

var usersListNoNPlus1 = entityManager.createQuery(
                "from User u left join fetch u.userCards",
                User.class).getResultList();

Mając listę użytkowników, dla każdego sprawdzisz ile ma kart – ale przecież nie potrzebowałeś w tej logice dociągać danych wszystkich kart.

Możesz zrobić to z wykorzystaniem @Formula

@Entity
public class User {
    @Id
    String userId;

    String firstName;

    String lastName;

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "CARD_OWNER_ID")
    List<Card> userCards;    
	
	@Formula("(SELECT COUNT(1) FROM SOFTWARESKILL.CARDS C WHERE C.CARD_OWNER_ID=USER_ID)")
    int cardsCount;
}

Dzięki temu do pola cardsCount zostanie wstrzyknięta liczba kart, a relacja może być zmieniona na LAZY.

Musisz zwrócić uwagę na to, iż zapytanie SQL dla @Formula to natywne zapytanie SQL, i może nie zadziałać na różnych rodzajach bazy danych, jeżeli będzie wykorzystywało jakąś specyfikę danego silnika bazodanowego.

Automatyczna data utworzenia i modyfikacji

W Hibernate istnieją dwie anotacje @CreationTimestamp oraz @UpdateTimestamp, które mogą być użyte do automatycznego nadawania wartości dla momentu utworzenia i modyfikacji danych encji.

@Entity
public class CreditCard {
    
	@Id
    @GeneratedValue(strategy = SEQUENCE, generator = "SEQ_CARDS")
    Long cardId;
    
    @Convert(converter = YesNoBooleanConverter.class)
    Boolean enabled;

    @Enumerated(EnumType.STRING)
    CardCountry cardCountry;

    BigDecimal balance;

    @Temporal(TemporalType.DATE)
    Calendar expiresAt;

    @Temporal(TemporalType.TIMESTAMP)
    @CreationTimestamp
    Calendar createdAt;

    @Temporal(TemporalType.TIMESTAMP)
    @UpdateTimestamp
    Calendar updatedAt;
}

Uwaga. Jeżeli chciałbyś wykorzystać te dane, to musisz użyć EntityManager.flush, gdyż wartość pola jest ustawiana dopiero przy flush lub commit. Inaczej będzie wartość null.

Przydatne linki

Wpis który czytasz to zaledwie fragment wiedzy zawartej w Programie szkoleniowym Java Developera od SoftwareSkill. Mamy do przekazania sporo usystematyzowanej wiedzy z zakresu kluczowych kompetencji i umiejętności Java Developera. Program składa się z kilku modułów w cotygodniowych dawkach wiedzy w formie video.

Wydajność Hibernate

Twórz szybko działające aplikacje z wydajną i zoptymalizowaną obsługą bazy danych.

Podoba Ci się ten artykuł? Weź więcej.

Jeżeli uważasz ten materiał za wartościowy i chcesz więcej treści tego typu – nie przegap ich i otrzymuj je prosto na swoją skrzynkę. Nawiążmy kontakt.

.

Gdybyś potrzebował jeszcze więcej:

Jesteś Java Developerem?

Przejdź na wyższy poziom wiedzy 
„Droga do Seniora” 🔥💪

Jesteś Team Leaderem? Masz zespół?

Podnieś efektywność i wiedzę swojego zespołu 👌

Dyskusja