@Cacheable
and @CachePut
. But, what about removing data from cache? Consider a call to delete the record from Service or DB, in which case, we would also want to delete that record from the cache.We have
@CacheEvict
to our rescue. When a method is annotated with @CacheEvict
, spring removes the data from the cache for the provided key, on the invocation of the method. @CacheEvict
supports all the attributes that @Cacheable
does. Plus it has a few more.Let's explore eviction through various examples.
First and foremost, the code we would use for our tests.
ActorService
, that provides the persistence for movie actors.public class ActorService {
@Cacheable(value = "actors", key = "#name")
public Actor getActor(String name) {
//The print that proves the method is executed.
System.out.println("getting actor " + name);
//retrieve the actor from DB and return
return new Actor(name, Gender.MALE);
}
//other methods
}
And the code to run the tests.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.codelooru.cache");
ActorService service = context.getBean("actorService", ActorService.class);
service.getActors("sean");
service.getActors("meryl");
service.getActors("sean");
service.getActors("meryl");
On the initial run, we would see the following output. getting actor sean
getting actor meryl
CacheEvict with Key
removeActor
method to the ActorService
as shown below. The method is annotated with @CacheEvict
with the value
set to the cachename, from which the data needs to be evicted. @CacheEvict(value = "actors", key = "#name")
public void removeActor(String name) {
System.out.println("--removedActor--");
}
And modify the test code as below and run it
service.getActor("sean");
service.getActor("meryl");
service.getActor("sean");
service.getActor("meryl");
service.removeActor("sean");
service.getActor("sean");
service.getActor("meryl");
This would result in
getting actor sean
getting actor meryl
--removedActor--
getting actor sean
In this example, we called
removeActor
with key = "sean"
, which removed sean from the cache. Therefore, the subsequent call to getActor
for sean resulted in the execution of the method, but the call with "meryl" did not.CacheEvict with conditions
Let's add a condition for eviction
@CacheEvict(value = "actors", key = "#name", condition="#name == 'meryl'")
public void removeActor(String name)
Running the test code would result in the following.
getting actor sean
getting actor meryl
--removedActor--
This means that the call to
removeActor
did not remove the data element from cache, as the condition was checking for the name to match 'meryl'.
Let's change the condition to 'sean'
@CacheEvict(value = "actors", key = "#name", condition="#name == 'sean'")
public void removeActor(String name)
Running the test code would result in the following
getting actor sean
getting actor meryl
--removedActor--
getting actor sean
Now, we see that the
removeActor
did remove the data element for 'sean' from the cache.
unless
works in a similar way, except that its expression evaluated after the execution of the method; thereby allowing you to use the result
of the method in the expression. See Part3 for more details on how unless
works.
CacheEvict with allEntries
removeActor
as shown below.
@CacheEvict(value = "actors", allEntries = true)
public void removeActor(String name)
Running the test code results in the following output.
getting actor sean
getting actor meryl
--removedActor--
getting actor sean
getting actor meryl
As you see, setting the
allEntries
attribute to true, removed all the data elements from the "actors" cache. Therefore, the subsequent calls with both sean and meryl result in the execution of the methods.
Final Notes
- Either
key
orallEntries
attribute should be present for cache eviction. - Do not use both
@Cacheable
and@CacheEvict
on a method. It does not solve any purpose. @CacheEvict
does not support retention based eviction e.g. evict LeastRecentlyUsed, LeastFrequentlyUsed, etc. For such policies, you will have to rely on 3rd party cache providers like ehCache.