Notatka: Cachowanie w Springu
Cachowanie – zapisywanie danych lub wyników jakiejś operacji (możliwe że długotrwałej lub łączącej się z bazą danych) w pamięci o lepszych parametrach w celu optymalizacji dostępu do danych (w najbliższym czasie) oraz odciążenia zasobów.
W samym hibernate istnieją trzy rodzaje cache: cache I poziomu (na poziomie sesji), cache II poziomu (na poziomie SessionFactory) oraz query cache (do cachowania zapytań do bazy danych).
Oprócz tego istnieje także Spring Cache, czyli cache na poziomie aplikacji.
Aby użyć cache w Springu należy (używając Spring Boot):
- pobrać zależnośći do projektu – Spring Cache oraz zewnętrznego providera, jednego z dostępnych który implementuje standard JSR-107 (inaczej JCache). Dostępni providerzy to: EhCache3, HazelCast, Caffeine. Można tez korzystać z Redisa, ja skorzystam z EhCache3.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
</dependency>
- dodać properties ze ścieżką konfiguracyjną do EhChache3 do application.properties (lub yaml jak ktoś woli)
spring.cache.ehcache.config=classpath:ehcache.xml
- dodać plik konfiguracyjny (który nazwałem ehcache.xml) do folderu resources, nagłówki xml można skopiować z dokumentacji EhCache3. Można też skonfigurować providera programowo
<cache-template name="default">
<key-type>java.lang.Long</key-type>
<expiry>
<ttl unit="minutes">30</ttl>
</expiry>
<resources>
<heap unit="entries">1000</heap>
<offheap unit="MB">500</offheap>
</resources>
</cache-template>
<cache alias="findAllBooks" uses-template="default"/>
<cache alias="findBookById" uses-template="default"/>
<cache alias="findAllPosts">
<expiry>
<ttl unit="minutes">10</ttl>
</expiry>
<heap unit="entries">500</heap>
</cache>
Jak widać można użyć cache-template i predefiniować sobie ustawienia lub dla każdego cache użyć innych ustawień jak np. czas po którym wpis z cache ma zostać usunięty.
- użyć adnotacji @Cacheable na metodzie którą chce się cachować, np. w taki sposób:
@Transactional
@Cacheable(cacheNames = "findBookById", key = "#id")
public Book findById(Long id) {
return bookRepository.findById(id).orElseThrow(
exceptionHelper.getEntityNotFoundException(id, Book.class));
}
I już, meotda (o nazwie cache która powinna być taka sama zarówno na metodzie jak i w pliku konfiguracyjnym) będzie cachowana po kluczu id!
Dodatkowe proste metody to:
@CachePut(cacheNames = "findBookById", key = "#result.id")
który służy do update wpisu w cache po danym kluczu, oraz
@CacheEvict(cacheNames = "findBookById")
która czyści cache o danej nazwie (można ustawić np. na metodzie usuwającej rekord z bazy danych).
Problem z @CachePut pojawia się jeśli chce się updatować całą kolekcję, nie ma wbudowanej adnotacji (z tego co mi wiadomo) i trzeba sobie radzić samemu. Ja po zasięgnięciu opinii ze StackOverFlow postanowiłem po prostu czyścić cache listy po update jednego rekordu. Może jest to trochę nadmiarowe jednak wydaję sie, że poprawne. Aby to zrobić trzeba wstrzyknąć CacheManager cachemanager;
a następnie wyczyścić cache metodą: cacheManager.getCache("findAllBooks").clear();
Narazie to tyle ile wiem na temat cache springowego, jeśli dowiem się coś więcej będę dopisywał w tym poście.
Linki:
Dokumentacja EhCache3: https://www.ehcache.org/documentation/3.0/
Cachowanie w Spring Boot: https://www.youtube.com/watch?v=lWv3uBLO2LU