Strategie współbieżności
Po włączeniu buforowania drugiego poziomu w Hibernate musisz wyjaśnić Hibernate, które obiekty Entity chcemy buforować i jak.
Aby to zrobić, Hibernate ma specjalną adnotację dla klas Entity - @Cache . Przykład:
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
Ta adnotacja musi zostać napisana dla każdej jednostki Entity, dla której chcemy użyć pamięci podręcznej drugiego poziomu. Przykład:
@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
@Id
private Integer id;
private Set<Task> tasks;
}
Hibernate ma 4 możliwe strategie dostępu do buforowanej jednostki, jeśli jest ona dostępna z różnych wątków:
- tylko czytać
- odczyt-zapis
- nieostry-odczyt-zapis
- transakcyjny
Tylko do odczytu . Dostosowana do danych strategia współbieżności, która nigdy się nie zmienia. Hibernate po prostu zapisze te obiekty w swojej pamięci. Użyj go tylko dla danych referencyjnych.
Bazy danych przechowują wiele informacji, które nigdy się nie zmieniają. Na przykład tabela zawiera listę zdarzeń, które są tylko dodawane, ale nigdy nie zmieniane ani usuwane. Jeśli musisz pracować z tą tabelą przez Hibernate, strategia buforowania tylko do odczytu będzie dla Ciebie odpowiednia.
Odczyt-zapis (odczyt-zapis). Użyj tej strategii dla danych, które są przede wszystkim czytelne. Jednak Hibernate będzie śledzić próby zmiany tych danych, chociaż spodziewa się, że będą one bardzo rzadkie.
Musisz buforować głównie te obiekty, które rzadko się zmieniają i są często odczytywane/żądane. Jeśli masz takie obiekty, musisz zastosować dla nich strategię odczytu i zapisu.
Nieostry-odczyt-zapis . Ta strategia nie gwarantuje spójności między pamięcią podręczną a bazą danych. Użyj tej strategii, jeśli dane prawie nigdy się nie zmieniają, a niewielka szansa na nieaktualne dane nie jest problemem krytycznym.
W przeciwieństwie do strategii odczytu i zapisu strategia ta zakłada, że zmienne dane nie są blokowane do odczytu. Może to spowodować, że obiekt zostanie zmieniony w jednym miejscu, podczas gdy w innym ktoś czyta jego starą wersję.
Na przykład użytkownik zmienił swój komentarz, ale inni użytkownicy nadal widzą jego starą wersję przez jakiś czas. Jeśli nie stanowi to dla Ciebie problemu, użyj strategii nonstrict-read-write.
transakcyjne . Tej strategii należy używać głównie w przypadku danych tylko do odczytu, w przypadku których ważne jest zapobieganie przestarzałym danym w równoczesnych transakcjach w rzadkich przypadkach aktualizacji.
Przechowywanie danych w pamięci podręcznej
Innym ważnym szczegółem dotyczącym pamięci podręcznej drugiego poziomu, o którym powinieneś pamiętać, jest to, że Hibernate nie przechowuje samych obiektów twoich klas. Przechowuje informacje w postaci tablic ciągów znaków, liczb itp.
A identyfikator obiektu działa jako wskaźnik do tych informacji. Koncepcyjnie jest to coś w rodzaju mapy, w której identyfikator obiektu jest kluczem, a tablice danych są wartością. Możesz to sobie wyobrazić tak:
1 -> { "Ivanov", 1, null , {1,2,5} }
2 -> { "Petrov", 2, null , {1,2,5} }
3 -> { "Sidorov", 3, null , {1,2,5} }
Co jest bardzo rozsądne, biorąc pod uwagę, ile dodatkowej pamięci zajmuje każdy obiekt.
Oprócz powyższego powinieneś pamiętać, że zależności twojej klasy Entity również nie są domyślnie buforowane. Na przykład, jeśli weźmiemy pod uwagę powyższą klasę Pracownik , to podczas pobierania kolekcja zadań zostanie pobrana z bazy danych , a nie z pamięci podręcznej drugiego poziomu .
Jeśli chcesz również buforować zależności, klasa powinna wyglądać tak:
@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
@Id
private Integer id;
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Task> tasks;
}
I ostatni szczegół - odczyt z pamięci podręcznej drugiego poziomu następuje tylko wtedy, gdy żądany obiekt nie został znaleziony w pamięci podręcznej pierwszego poziomu.
Tryb pamięci podręcznej
Hibernacja pozwala na bardzo elastyczne zarządzanie pamięcią podręczną. Możesz ustawić tryb pamięci podręcznej dla każdej sesji lub nawet dla każdego żądania bazy danych.
Istnieje pięć takich trybów:
- DOSTAWAĆ
- IGNOROWAĆ
- NORMALNA
- UMIEŚCIĆ
- ODŚWIEŻAĆ
Poniższa tabela opisuje ich pracę:
Tryb pamięci podręcznej | Opis |
---|---|
DOSTAWAĆ | Dane są odczytywane z pamięci podręcznej, ale nie są do niej dodawane. |
IGNOROWAĆ | Sesja nie wchodzi w interakcję z pamięcią podręczną. |
NORMALNA | Dane są odczytywane z pamięci podręcznej i dodawane do niej. |
UMIEŚCIĆ | Dane nigdy nie są pobierane z pamięci podręcznej, ale do niej dodawane. |
ODŚWIEŻAĆ | Dane nigdy nie są pobierane z pamięci podręcznej, ale do niej dodawane. W tym trybie dodatkowo używane jest ustawienie hibernate.cache.use_minimal_puts. |
Przykład ustawienia trybu pamięci podręcznej dla sesji:
session.setCacheMode(CacheMode.GET);
Employee director = session.createQuery("from Employee where id = 4").uniqueResult();
A także przykład ustawienia trybu dla sesji i żądania:
session.setCacheMode(CacheMode.GET);
Query query = session.createQuery("from Employee where id = 4");
query.setCacheMode(CacheMode.IGNORE); // Ignore cache work for this request
Employee director = query.uniqueResult();