Careeroza
Caching Concepts
Why Cache
The product detail page of ShopEase is read thousands of times a minute but changes maybe once a day. Reading it from MySQL every time wastes database time. A cache keeps the answer in fast memory and returns it directly next time.
| Term | Meaning |
|---|---|
| Hit | the value was found in the cache |
| Miss | not found: call the real method / database, then store the result |
| TTL | time to live: how long an entry stays valid |
| Eviction | removing entries (on update, on TTL expiry, or when the cache is full: LRU) |
| Stale data | cache still holds an old value after the database changed |
A Cache with TTL in Plain Java
Example
This is what a cache does inside. A fake clock makes the output deterministic, so we can "move time forward" past the TTL:
import java.util.*;
import java.util.function.*;
public class Main {
static long now = 0; // fake clock in seconds
public static void main(String[] args) {
TtlCache<Long, String> cache = new TtlCache<>(60, () -> now);
Function<Long, String> loadFromDb = id -> {
System.out.println(" DB query for product " + id);
return "Product#" + id;
};
System.out.println(cache.get(1L, loadFromDb)); // miss
now = 30;
System.out.println(cache.get(1L, loadFromDb)); // hit
now = 61;
System.out.println(cache.get(1L, loadFromDb)); // expired -> miss
cache.evict(1L);
System.out.println(cache.get(1L, loadFromDb)); // evicted -> miss
System.out.println("hits=" + cache.hits + " misses=" + cache.misses);
}
}
class TtlCache<K, V> {
private record Entry<V>(V value, long expiresAt) {}
private final Map<K, Entry<V>> map = new HashMap<>();
private final long ttl;
private final LongSupplier clock;
int hits, misses;
TtlCache(long ttlSeconds, LongSupplier clock) { this.ttl = ttlSeconds; this.clock = clock; }
V get(K key, Function<K, V> loader) {
Entry<V> e = map.get(key);
if (e != null && e.expiresAt() > clock.getAsLong()) { hits++; return e.value(); }
misses++;
V value = loader.apply(key);
map.put(key, new Entry<>(value, clock.getAsLong() + ttl));
return value;
}
void evict(K key) { map.remove(key); }
}Output
DB query for product 1 Product#1 Product#1 DB query for product 1 Product#1 DB query for product 1 Product#1 hits=1 misses=3
What to Cache (and What Not)
- Good: product details, category lists, configuration, exchange rates, results of slow external APIs.
- Careful: stock count and prices (short TTL, or evict on every change).
- Never: per-request security decisions, payment status, anything that must be exactly current.
Tip: First measure. Cache the few slow, frequently read things, not everything.