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?
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.
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.
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.
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);
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
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 {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With