Caching in Java: Redis, Caffeine, Ehcache — Complete Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Caching in Java: Redis, Caffeine, Ehcache, and JCache



Caching is one of the key tools for improving the performance of Java applications. It reduces response time, lowers the load on databases and external APIs. In this article, we will cover three popular solutions: Redis (external distributed cache), Caffeine (high-performance in-memory cache), and Ehcache (hybrid cache with disk support). We will also look at the JCache (JSR 107) standard, which unifies working with caches.



Why is caching needed in Java?

Main use cases:

  • Reducing latency — data from the cache is returned in microseconds, not milliseconds (as with a database query).
  • Reducing load — the cache protects the database from repeated queries.
  • Saving resources — fewer calls to external services means lower infrastructure costs.


1. Redis — distributed cache for microservices

Redis is an in-memory data store often used as a distributed cache. It supports various data structures: strings, hashes, lists, sets. For Java, there are two main clients: Jedis and Lettuce (recommended for Spring Boot).



Example of connecting via Spring Data Redis:

@Configurationpublic class RedisConfig {    @Bean    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {        RedisTemplate<String, Object> template = new RedisTemplate<>();        template.setConnectionFactory(connectionFactory);        template.setKeySerializer(new StringRedisSerializer());        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());        return template;    }}

@Servicepublic class UserService { @Autowired private RedisTemplate<String, Object> redisTemplate;

public User getUserById(String id) { String key = "user:" + id; User cached = (User) redisTemplate.opsForValue().get(key); if (cached != null) return cached;

User user = database.findUserById(id); // expensive query redisTemplate.opsForValue().set(key, user, 10, TimeUnit.MINUTES); return user; }}


Pros of Redis: distributed, TTL support, pub/sub, persistence. Cons: network latency, server memory consumption.



2. Caffeine — ultra-fast in-memory cache

Caffeine is a library for local caching based on the W-TinyLFU algorithm. It provides nearly 100% hit rate with minimal memory consumption. Ideal for single-threaded and multi-threaded applications.



Example of using Caffeine:

Cache<String, User> cache = Caffeine.newBuilder()    .expireAfterWrite(5, TimeUnit.MINUTES)    .maximumSize(10_000)    .recordStats()    .build();

public User getUser(String id) { return cache.get(id, key -> database.findUserById(key));}

// Getting statisticsCacheStats stats = cache.stats();System.out.println("Hit rate: " + stats.hitRate());


Pros of Caffeine: minimal latency (nanoseconds), built-in statistics, automatic eviction of old entries. Cons: local cache only, not suitable for distributed systems.



3. Ehcache — hybrid cache with disk storage

Ehcache is one of the oldest caching libraries for Java. It supports in-memory and disk caching, as well as clustering via Terracotta. Often used in conjunction with Hibernate.



Example of Ehcache 3 configuration (XML):

<config xmlns:xsi="http://www.w3.org                    

Recommendations