Caching & jenseits von JPA
Springs Caching-Abstraktion mit @Cacheable sowie wann man zu JdbcClient, MongoDB oder Redis greift.
Deutsche Übersetzung in Arbeit
Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.
Auf dieser Seite
JPA is the default for relational data, but the Spring Data family is bigger, and one cross-cutting concern - caching - can speed up any of it. This lesson rounds out the Data module with the tools you'll reach for beyond plain JPA.
Caching with @Cacheable
Some reads are expensive and repeated with the same inputs - a rarely-changing lookup, an aggregation. Spring's caching abstraction stores the result so repeat calls skip the work entirely:
@Service
class CatalogStats {
@Cacheable("bookCountByAuthor")
public long countByAuthor(String author) { // runs once per author…
return bookRepository.countByAuthor(author); // …then served from cache
}
@CacheEvict(value = "bookCountByAuthor", allEntries = true)
public void onCatalogChanged() { } // clear the cache when data changes
}Enable it with @EnableCaching on a config class. @Cacheable caches by method
arguments; @CacheEvict clears entries when the underlying data changes.
If someone asks you a hard sum and then asks the exact same sum a minute later, you
don't recompute it - you remember. @Cacheable gives your method that memory: the first
call does the work, and identical later calls return the remembered answer instantly.
@CacheEvict is you forgetting the answer when the numbers change, so you don't repeat a
stale one.
Cache invalidation is the hard part
A cache that returns stale data is worse than no cache. Evict or update entries whenever the source changes, keep cached data reasonably short-lived, and only cache reads that are genuinely expensive and repeated - not everything.
Beyond JPA
JPA/Hibernate isn't always the right tool. The Spring Data ecosystem covers more:
| Need | Reach for |
|---|---|
| Full ORM over relational data | Spring Data JPA (the default) |
| Simple, explicit SQL without an ORM | JdbcClient (fluent JDBC in Spring 6.1+) |
| Document data | Spring Data MongoDB |
| Caching / ephemeral key-value | Spring Data Redis |
The beautiful part: they share the same repository programming model. A
MongoRepository or Spring Data Redis repository looks and feels like the
JpaRepository you already know - so the concepts from this module transfer directly.
// JdbcClient — when you want plain SQL, no entity mapping overhead
List<Book> books = jdbcClient
.sql("SELECT * FROM book WHERE copies > :min")
.param("min", 0)
.query(Book.class)
.list();For each BookVault read, decide whether @Cacheable is a good fit, and if so what would invalidate the cache:
- A homepage stat: "total books in the catalog," changing at most a few times a day.
- A member's current list of active loans, which changes every time they borrow or return.
What does @Cacheable do on a method?
Key takeaways
- Spring's caching abstraction (@EnableCaching + @Cacheable) stores method results by arguments so repeated calls skip the work.
- Invalidate with @CacheEvict when the underlying data changes - stale cache data is worse than none.
- Only cache reads that are genuinely expensive and repeated, and keep cached data reasonably fresh.
- Beyond JPA: JdbcClient for plain SQL, Spring Data MongoDB for documents, Spring Data Redis for key-value/caching.
- All Spring Data modules share the same repository model, so the concepts transfer across databases.