Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Cacheable not caching

Using Spring 3.2 with EhCache 2.9. I've annotated a zero-parameter method as follows:

@Cacheable(value="myList", key="#result.method.name")
protected List<MyObject> getMyList() {
   //db query
   //return list of results
}

EhCache config:

<cache name="myList"
    statistics="true"
    maxEntriesLocalHeap="1"     
    timeToLiveSeconds="3600">
    <persistence strategy="none" />
</cache> 

I'd like the database results to be cached. Since this method has no parameters, I've chosen the method name to be the cache key.

When I test this, the database is hit every method invocation and I'm not sure why. Any ideas?


UPDATE

So after troubleshooting I found something interesting. Currently the getMyList method (on which the caching is defined) is in the same class that calls it. That method basically calls a DAO to query for the list. If I move getMyList outside to another class which just acts as a proxy, and then I change the original invoker to call this new proxy instead, then the caching works. I can't explain why. Any input?

like image 396
user1491636 Avatar asked Oct 07 '15 14:10

user1491636


2 Answers

Imagine you go to the Zoo. You go through the entrance once and pay your entry. Afterwards you can visit the Lions, the Tigers, and so on... You don't have to pay everytime because you did it when you entered. If you get bored and want to go to another Zoo, you have to go out, go to the next one, and pay again.

Your Class is the Zoo, your Methods are the Animals, and the Cache Proxy is the Entrance. When someone calls your class, it goes through the Cache once. When she is in, and calls another methods of the same class, it doesn't go through the Cache again. Only when you go out and in again, you go through the Cache.

There is a nasty trick you can use to override this called inject yourself:

public class YourClass {
    @Autowired
    private YourClass instance;

    @Cacheable
    public String method1() {
          // now you go through the cache again
          return instance.method2();
    }

    @Cacheable
    public String method2() {
          return "2";
    }
}
like image 86
Ruben Avatar answered Sep 17 '22 13:09

Ruben


Ruben's answer is definitely correct, however I'll add something else that might be giving others trouble (like it did me). The annotation only seems to apply to public methods. It won't work on package protected even if it's in a different class.

like image 25
KC Baltz Avatar answered Sep 18 '22 13:09

KC Baltz