KidA78
KidA78

Reputation: 190

EhCache: @CacheEvict on Multiple Objects Using Annotations

I understand that using Spring's (3.1) built in CacheManager using the EhCache implementation, there are certain limitations when in proxy mode (the default) as per this post:

Spring 3.1 @Cacheable - method still executed

Consider the scenario I have:

@CacheEvict(value = "tacos", key = "#tacoId", beforeInvocation = true)
removeTaco(String tacoId) {
    // Code to remove taco
}

removeTacos(Set<String> tacoIds) {
    for (String tacoId : tacoIds) {
        removeTaco(tacoId); 
    }
}

In this repository method, calling removeTacos(tacoIds) will not actually Evict anything from the Cache because of the limitation described above. My workaround, is that on a service layer above, if I wanted to delete multiple tacos, I'd be looping through each taco Id and passing it into removeTaco(), and never using removeTacos()

However, I'm wondering if there's another way to accomplish this.

1) Is there an SpEL expression that I could pass into the key that would tell EhCache to expire every id in the Set?

e.g.  @CacheEvict(value = "tacos", key = "#ids.?[*]") // I know this isn't valid, just can't find the expression.

Or is there a way I can have removeTacos() call removeTaco and actually expire the Cached objects?

Upvotes: 1

Views: 9183

Answers (3)

Nader
Nader

Reputation: 37

The @Caching annotation can be used to combine multiple annotations of the same type such as @CacheEvict or @CachePut, this is the example from the Spring documentation

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)

Upvotes: 4

Ryan
Ryan

Reputation: 101

You can do one of two things

@CacheEvict(value = "tacos", allEntries = true)
removeTacos(Set<String> tacoIds)

which is not so bad if tacos are read a lot more than they are removed

OR

removeTacos(Set<String> tacoIds) {
    for (String tacoId : tacoIds) {
        getTacoService().removeTaco(tacoId); 
    }
}

by calling the service (proxy) you invoke the cache eviction.

Upvotes: 2

ragnor
ragnor

Reputation: 2528

AFAIK @CacheEvict supports only removing single entry (by key) or all entries in given cache, there's no way to remove at once multiple entries. If you want to put, update or remove multiple objects from cache (using annotations) and you may switch to memcached take a look at my project Simple Spring Memcached (SSM).

Self invocations don't go through the proxy so one of the solution is to switch to other mode than proxy. Anther solution (I'm not recommending it) may be keeping reference to the service in service (as an autowired field) and use it to invoke removeTaco.

Several months ago I had similar issue in one of my projects. It didn't use Spring Cache but SSM which also requires proxy. To made it work I moved caching (annotations) from service to DAO (repositories) layer. It solved problem with self invocation.

Upvotes: 1

Related Questions