Blaine
Blaine

Reputation: 177

Are Spring's cache annotations safe to use when evictions are involved?

I am using Spring 4.0.3, and utilizing the Cache Abstraction feature, backed by EhCache 2.8.1.

I was concerned that the method-level annotations @Cacheable and @CacheEvict may not properly lock the cache while editing it, resulting in thread safety problems. My test below seems to confirm that. My question is, am I misusing the framework or misinterpreting the results of my test? Or am I correct in concluding that the annotations do not cause the cache to be properly locked, and therefore the use of @CacheEvict does not guarantee that future reads will be valid?

Test:

Create a database table to store a counter value

create table counter
(
    counter integer
);
insert into counter values(0);

Create an entry in ehcache.xml to cache the counter value

<cache name="counter"
    eternal="true"
    maxElementsInMemory="1"/>

Create two request mapping methods in a Spring controller -- one to read the value of the counter and return after a long delay, and the other to increment the value and then return quickly

@RequestMapping("/viewcounter")
@ResponseBody
@Cacheable(value = "counter", key = "1")
public int readCounter() {
    int count = dao.selectInteger("select counter from counter");
    try {
        Thread.sleep(5000);
    }
    catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return count;
}

@RequestMapping("/incrementcounter")
@ResponseBody
@CacheEvict(value = "counter", key = "1")
public int incrementCounter() {
    dao.update("update counter set counter = counter + 1");
    int count = dao.selectInteger("select counter from counter");
    return count;
}

Follow these three steps under two different scenarios -- first with the cache annotations removed from the controller methods, and then with them added back in

  1. Visit /incrementcounter
  2. In one browser tab, visit /viewcounter, and then immediately after initiating this request, visit /incrementcounter in another tab
  3. Visit /viewcounter

Test results

Expected result: 2
Actual result without caching: 2
Actual result with caching: 1

The with-caching result is wrong, yes?

Upvotes: 2

Views: 3067

Answers (1)

Stephane Nicoll
Stephane Nicoll

Reputation: 33101

There's no locking in the cache abstraction. You are not the first one asking for it and we already had significant brainstorming internally of what it would cost to support it. It turns out that it is far from being simple and playing with locks in such abstraction may be very tricky, especially in a "generic" way. Also, cache vendors spend a significant amount of resources to support these kind of use cases and there's a reason for that.

My best guess at it for the moment is that if you want these features, you need your cache to be transactional. There are some gotcha when using it with the abstraction though, check in particular SPR-11540 which is being worked on at the moment.

Upvotes: 1

Related Questions