在涉及驱逐时,Spring的缓存注释是否可以安全使用?

时间:2014-05-23 13:12:13

标签: java spring caching spring-cache

我正在使用Spring 4.0.3,并使用由EhCache 2.8.1支持的缓存抽象功能。

我担心方法级注释@Cacheable@CacheEvict在编辑时可能无法正确锁定缓存,从而导致线程安全问题。我的测试似乎证实了这一点。我的问题是,我是否滥用了框架或误解了我的测试结果?或者我是否正确得出结论,注释不会导致缓存被正确锁定,因此使用@CacheEvict并不能保证将来的读取有效?

测试:

创建数据库表以存储计数器值

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

在ehcache.xml中创建一个条目以缓存计数器值

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

在Spring控制器中创建两个请求映射方法 - 一个用于读取计数器的值并在长时间延迟后返回,另一个用于递增值然后快速返回

@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;
}

在两种不同的情况下执行以下三个步骤 - 首先从控制器方法中删除缓存注释,然后将其添加回

  1. 访问/incrementcounter
  2. 在一个浏览器标签中,访问/viewcounter,然后在发起此请求后立即访问另一个标签中的/incrementcounter
  3. 访问/viewcounter
  4. 测试结果

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

    with-caching结果是错误的,是吗?

1 个答案:

答案 0 :(得分:1)

缓存抽象中没有锁定。你是not the first one asking for it我们已经在内部进行了大量的头脑风暴,以支持它所需的成本。事实证明,它远非简单,在这种抽象中使用锁可能非常棘手,特别是在&#34;泛型&#34;办法。此外,缓存供应商花费大量资源来支持这类用例,这就是原因。

我现在最好的猜测是,如果你想要这些功能,你需要你的缓存是事务性的。虽然在使用抽象时有一些问题,但请特别检查当前正在处理的SPR-11540