Junior
What is caching?
sobes.tech AI
Answer from AI
Caching is the process of storing copies of data in a fast-access location to reduce the time needed to retrieve it later. It helps avoid repeated costly operations such as reading from a database or performing complex calculations.
There are different levels and strategies of caching:
- Built-in caching:
- JVM caches bytecode.
- The processor caches data and instructions in registers and L1, L2, L3 caches.
- At the application level:
- In-memory caches (e.g., using Ehcache, Guava Cache, Caffeine).
- Distributed caches (e.g., using Redis, Memcached, Hazelcast).
- At the data level:
- Caching database query results.
- Caching ORM objects (e.g., first and second level cache in Hibernate).
- At the network level:
- Proxy servers cache responses from web servers.
- Browsers cache web resources.
- At the operating system level:
- Filesystem caching.
Main caching strategies:
- Read-through: Data is retrieved from the cache. If not present, the cache loads it from the primary source and returns it to the client.
- Write-through: Data is written simultaneously to the cache and the primary source.
- Write-back: Data is written only to the cache. Periodically or upon eviction, data is synchronized with the primary source.
- Write-around: Data is written only to the primary source, bypassing the cache.
The choice of strategy depends on the nature of data usage and consistency requirements.
Example of using cache for frequently accessed data:
// Example using Guava Cache
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.concurrent.ExecutionException;
public class DataService {
private LoadingCache<String, String> dataCache; // Cache with automatic loading
public DataService() {
dataCache = CacheBuilder.newBuilder()
.maximumSize(1000) // Maximum number of elements
.expireAfterWrite(10, java.util.concurrent.TimeUnit.MINUTES) // Cache lifetime
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
// Logic to load data from a "slow" source (e.g., database)
System.out.println("Loading data for key: " + key);
return loadFromDatabase(key);
}
});
}
public String getData(String key) throws ExecutionException {
// Get data from cache or load if absent
return dataCache.get(key);
}
private String loadFromDatabase(String key) {
// Simulate slow database load
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Data for " + key;
}
public static void main(String[] args) throws ExecutionException {
DataService service = new DataService();
System.out.println(service.getData("user1")); // Load and cache
System.out.println(service.getData("user1")); // Retrieve from cache
System.out.println(service.getData("user2")); // Load and cache
}
}
Caching improves performance and reduces load on primary data sources but also adds complexity (cache lifecycle management, invalidation, consistency).