I have a method that saves cache.
@GetMapping("/orders")
@Cacheable(value = "List<Order>", key = "{#customerName+'s orders', #page, #size}")
public List<Order> findOrders(@RequestParam("customerName") String customerName,
@RequestParam(name = "page") int page,
@RequestParam(name = "size") int size) {
...
And I want to remove this cache after calling of this method.
@PostMapping("/order")
@CacheEvict(value = "*",key="{#makeOrderDTO.customerDTO.name+'s orders', '', 'regex:*'}")
public Order makeOrder(@RequestBody MakeOrderDTO makeOrderDTO) {
I have a problem that I want to remove all cached pages for customers, but I can’t remove only one type of page. So I need to remove customers with all pages sizes and numbers. Maybe there is some kind of functionality like
@PostMapping("/order")
@CacheEvict(value = "*",key="{#makeOrderDTO.customerDTO.name+'s orders', 'regex:*', 'regex:*'}")
public Order makeOrder(@RequestBody MakeOrderDTO makeOrderDTO) {
or
@PostMapping("/order")
@CacheEvict(value = "*",key="{#makeOrderDTO.customerDTO.name+'s orders', 'any', 'any'}")
public Order makeOrder(@RequestBody MakeOrderDTO makeOrderDTO) {
Thanks in advance.
2
Answers
You couldn’t do this, because all cache technology uses key-value store. So if you use multiple parameters for key like this:
Spring creates a hash as key, for example: -172893112.
Ref: https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/cache.html#cache-annotations-cacheable-default-key
I recommend to you that change the cache name to use "’List’ + #customerName+’s orders’" but that is not supported using annotations at least that you use CacheResolver. See here.
After that, the evict method should be:
You could check this another post: Cache evict on one of multiple keys
Looking at your initial method:
Guessing from the signature, the method is doing many things:
If the pagination parameter varies, you may retrieve and cache the same order multiple times. Once making a new order, you would need to re-read the previous orders, that were not changed. That is sub optimal.
I suggest separating the concerns of data access and caching the data and servicing the web request in two classes or layers, since the web layer sits on top of the data access layer.
Also, always use ids and not the customer name as key, since names may have duplicates and also change (yes, it happens! Typos, marriage and company mergers).
For caching query results I always suggest caching the query result and the data separately. E.g. in your case in the data access layer:
Use two separate caches for it.
You can then implement the pagination in the REST layer.
When placing a new order, the query result with the order list becomes invalid. You can either add the ID, or use evict to invalidate the query result cache. However, this will not effect the cache with the actual order data.
I left out the actual Spring caching annotations. As soon as you have sorted the interfaces, these should be simple and straight forward.