I want to cache some db data. for example Cache Customer
and use customer.id
as the key.
How could I set the key if I want to load all customers (allCustomer()
in the code) ?
@Cacheable(value = "customer", key = "#customerID")
public Customer getCustomer(Long customerID) {
return getCustomerData(customerID);
}
// How to setup this key?
@Cacheable(value = "customer", key = "?")
public List<Customer> allCustomer(){
return db.values().stream().collect(Collectors.toList());
}
@CachePut(value = "customer", key = "#customer.id")
public void updateCustomer(Customer customer){
db.put(customer.getId(), customer);
}
@CacheEvict(value = "customer", key = "#customerID")
public void deleteCustomer(Long customerID){
db.remove(customerID);
}
CodePudding user response:
I would recommend using @CachePut
instead of @Cacheable
. In the case that a new entry is added to the DB from outside of this application instance, the cache would not contain that new value.
You can use #result.id
to tell Spring which value to use as a key and I've included a conditional so that you don't get strange errors in case of a null value.
@CachePut(value = "customer", key = "#result.id", condition = "#result != null")
CodePudding user response:
It's impossible to do it for collections with the Spring's annotations - with @Cacheable
you'd have just one element in a cache with a computed key and a value with the whole list inside.
If performance is not that important in your app, use getCustomer(...)
in a loop.
Otherwise, you'll need to update your cache manually. Unfortunately, Cache interface doesn't provide a method to retrieve all keys/values/key-value pairs from a cache, so a bit of casting is required.
The example for the default in-memory cache (spring.cache.type=simple
):
@Autowired
private org.springframework.CacheManager cacheManager;
public List<Customer> allCustomers() {
ConcurrentMap<Long, Customer> customerCache = (ConcurrentMap<Long, Customer>)
cacheManager.getCache("customer").getNativeCache();
if (!customerCache.isEmpty()) {
return new ArrayList<>(customerCache.values());
}
List<Customer> customers = db.values().stream().collect(Collectors.toList());
customers.forEach(customer -> customerCache.put(customer.getId(), customer));
return customers;
}
Or for spring.cache.type=jcache
with backed EhCache 3:
@Autowired
private org.springframework.CacheManager cacheManager;
public List<Customer> allCustomers() {
javax.cache.Cache<Long, Customer> customerCache = (javax.cache.Cache<Long, Customer>)
cacheManager.getCache("customer").getNativeCache();
Iterator<Cache.Entry<Long, Customer>> iterator = customerCache.iterator();
List<Customer> cachedCustomers = new ArrayList<>();
while (iterator.hasNext()) {
Cache.Entry<Long, Customer> entry = iterator.next();
cachedCustomers.add(entry.getValue());
}
if (!cachedCustomers.isEmpty()) {
return cachedCustomers;
}
List<Customer> customers = db.values().stream().collect(Collectors.toList());
customers.forEach(customer -> customerCache.put(customer.getId(), customer));
return customers;
}
The same can be done similarly for any other cache type (redis, hazelcast, caffeine etc.).
The corresponding eviction method can be written much easier:
@CacheEvict(value = "customer", allEntries = true)
public void deleteAllCustomers(){
db.removeAll(); //pseudocode
}