Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Cache Evict does not work

Hi I have problem with clean cache when method is executed. Here is my configuration and caches methods:

@Configuration
@EnableCaching
@AutoConfigureAfter(value = {MetricsConfiguration.class, DatabaseConfiguration.class})
@Profile("!" + Constants.SPRING_PROFILE_FAST)
public class CacheConfiguration {

    private final Logger log = LoggerFactory.getLogger(CacheConfiguration.class);
    public static final String STOCK_DETAILS_BY_TICKER_CACHE = "stockDetailsByTickerCache";
    public static final String RSS_NEWS_BY_TYPE_CACHE = "rssNewsByTypeCache";

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List<Cache> caches = new ArrayList<Cache>();
        caches.add(new ConcurrentMapCache(STOCK_DETAILS_BY_TICKER_CACHE));
        caches.add(new ConcurrentMapCache(RSS_NEWS_BY_TYPE_CACHE));
        cacheManager.setCaches(caches);
        return cacheManager;
    }
}

This method i want to cache:

@Cacheable(cacheNames = CacheConfiguration.RSS_NEWS_BY_TYPE_CACHE, key = "#type")
    public ResponseEntity<List<NewsDetailsDTO>> getLatestNewsMessageByType(RssType type) {
        Pageable pageable = new PageRequest(0, 5, Sort.Direction.DESC, "createdDate");
        List<NewsMessage> latestNewsMessage = newsMessageRepository.findByType(type, pageable).getContent();
        return new ResponseEntity<List<NewsDetailsDTO>>(mapToDTO(latestNewsMessage), HttpStatus.OK);
    }

On execution of this method i would like to clean cache by type:

@CacheEvict(cacheNames={CacheConfiguration.RSS_NEWS_BY_TYPE_CACHE}, beforeInvocation = true, key = "#news.type")
    public void save(NewsMessage news) {
        newsMessageRepository.save(news);
    }

And NewsMessage object looks like:

@Entity
@Table(name = "NEWS_MESSAGE")
public class NewsMessage extends ChatMessage {

    <other fileds>

    @NotNull
    @Enumerated(EnumType.STRING)
    private RssType type;
}

The cache thing works fine, by the first time there is a query to DB by second and next the data is fetch from cache. Problem is when I update data the @CacheEvict does not clean the cache. I was trying to clean all cache using this annotation: @CacheEvict(cacheNames={CacheConfiguration.RSS_NEWS_BY_TYPE_CACHE}, allEntries = true) But it also does not work. Could you help me?

like image 502
Pulkownik Avatar asked May 03 '16 16:05

Pulkownik


People also ask

How do I evict a spring cache?

2. How to Evict a Cache? Spring provides two ways to evict a cache, either by using the @CacheEvict annotation on a method, or by auto-wiring the CacheManger and clearing it by calling the clear() method.

How do you cause a cache eviction?

To automatically enable cache eviction, define a fileset soft quota on the cache fileset. Eviction starts when fileset usage reaches the soft quota limit. A time lag might result when an eviction is triggered and the data is evicted.

How ehcache works in spring boot?

EhCaching Storage Tiers are as follows: On-Heap Store: Java heap memory is used to store cache entries. Off-Heap Store: It stores cache entries into primary memory (RAM). Disk Store: It uses a disk to store cache entries. Clustered Store: Remote server is used to store cache entries.

What is use of @CacheEvict?

The @CacheEvict annotation is used only to perform cache eviction. Let's see how this annotation makes the remove() method of AccountRepository as a cache eviction: @CacheEvict("accountCache ") void remove(Long accountId);


2 Answers

From where do you call the save() method?

In your own answer it looks like you have moved the annotations to another class/interface to invoke the proxy object of that class/interface (btw annotations should generally not be used in interfaces, because they often don't get catched with default configuration).

Therefore my question: do you know the spring aop proxy? You have to call annotated methods from methods outside your MessageRepository class to invoke the proxy object.

General documentation for that is here: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-understanding-aop-proxies

or with examples here http://spring.io/blog/2012/05/23/transactions-caching-and-aop-understanding-proxy-usage-in-spring

like image 162
beendr Avatar answered Nov 14 '22 23:11

beendr


I found the workaround for my problem. I had to moved the annotation upper to the spring data jpa interace.

public interface NewsMessageRepository extends JpaRepository<NewsMessage, Long> {

    @CacheEvict(cacheNames = {CacheConfiguration.RSS_NEWS_BY_TYPE_CACHE}, beforeInvocation = true, key = "#p0.type")
    NewsMessage save(NewsMessage news);
}

Now it is working as i expected, but still have no idea why it did not work in my service. Maybe because my services implements two interfaces?

@Service
public class NewsMessageService implements RssObserver, NewsMessageServiceable {
}
like image 36
Pulkownik Avatar answered Nov 14 '22 22:11

Pulkownik