Spring Cacheable vs CachePut?

2020-02-09 01:08发布

问题:

@CachePut or @Cacheable(value = "CustomerCache", key = "#id")
public Customer updateCustomer(Customer customer) {
   sysout("i am inside updateCustomer");
    ....
    return customer;
}

I found below documentation under CachePut source code

CachePut annotation does not cause the target method to be skipped - rather it always causes the method to be invoked and its result to be placed into the cache.

Does it mean if I use @Cacheable , updateCustomer method will be executed only once and result will be updated in cache. Subsequent calls to updateCustomer will not execute updateCustomer , it will just update the cache.

While in case of @CachePut, updateCustomer method will be executed on each call and result will be updated in cache.

Is my understanding correct?

回答1:

Yes.

I even made a test to be sure:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CacheableTest.CacheConfigurations.class)
public class CacheableTest {

    public static class Customer {

        final private String id;
        final private String name;

        public Customer(String id, String name) {
            this.id = id;
            this.name = name;
        }

        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }

    }

    final public static AtomicInteger cacheableCalled = new AtomicInteger(0);
    final public static AtomicInteger cachePutCalled = new AtomicInteger(0);

    public static class CustomerCachedService {


        @Cacheable("CustomerCache")
        public Customer cacheable(String v) {
            cacheableCalled.incrementAndGet();
            return new Customer(v, "Cacheable " + v);
        }

        @CachePut("CustomerCache")
        public Customer cachePut(String b) {
            cachePutCalled.incrementAndGet();
            return new Customer(b, "Cache put " + b);
        }

    }

    @Configuration
    @EnableCaching()
    public static class CacheConfigurations {

        @Bean
        public CustomerCachedService customerCachedService() {
            return new CustomerCachedService();
        }

        @Bean
        public CacheManager cacheManager() {
            return new GuavaCacheManager("CustomerCache");
        }

    }

    @Autowired
    public CustomerCachedService cachedService;

    @Test
    public void testCacheable() {
        for(int i = 0; i < 1000; i++) {
            cachedService.cacheable("A");
        }
        Assert.assertEquals(cacheableCalled.get(), 1);
    }

    @Test
    public void testCachePut() {
        for(int i = 0; i < 1000; i++) {
            cachedService.cachePut("B");
        }
        Assert.assertEquals(cachePutCalled.get(), 1000);
    }

}


回答2:

@CachePut always lets the method execute. It is generally used if you want your cache to be updated with the result of the method execution.
Example: When you want to update a stale data which is cached, instead of blowing the cache completely.

@Cacheable will be executed only once for the given cachekey and subsequent requests won't execute the method, until the cache expires or gets flushed.



回答3:

Yes, you are absolutely correct.

@Cacheput and @Cacheable are used in conjunction.

@Cacheable will not update the cache on every call. In order to remove the stale data, there must be a service that uses the @Cacheput that clears the stale data.

Below answer is for the ones who are using guava caching to build cache. Using guava caching, the time interval that is applied will empty the cache after a certain period of time which is not the case with @Cacheput. @Cacheput will only update the values that are stale and hence it calls the method every time to update the cache.

I hope my answer clears your question.