Spring Cache – @CacheEvict, @CachePut not working while calling from the another method from the same class

huangapple go评论93阅读模式
英文:

Spring Cache - @CacheEvict, @CachePut not working while calling from the another method from the same class

问题

Spring缓存在调用同一类的另一个方法中的缓存方法时不起作用。

以下是一个示例,以清楚的方式解释我的问题。

缓存的服务类:

class testServiceImpl {

    @CachePut(key = "#result.id", condition = "#result != null")
    public List<String> create(String input) {
        // ...
    }

    @CacheEvict(key="#id")
    public void deleteById(Long id) {
        // ...
    }

    public void multiDelete(String input) {
        if (condition...) {
            deleteById(2);  // 缓存在这里没有被清除,即记录仍然存在于getAll调用中,但数据库中没有了。
        } else {
            create(input); // 新数据在数据库中持续存在,但在缓存中没有被更新。
        }
    }

    @Transactional
    @Cacheable
    public Map<Long, String> getAll() {
        // ...
    }
}

我还尝试过以下解决方案,但未成功。

// 创建同一类的新对象并使用它。在这种情况下,数据在数据库中没有持续存在,即它不会从数据库中删除数据。
testServiceImpl testService;
// ...
public void multiDelete(String input) {
    if (condition...) {
        testService.deleteById(2);
    } else {
        testService.create(input);
    }
}

有人能帮助我解决这个问题吗?

英文:

Spring cache is not working when calling cached method from another method of the same class.

Here is an example to explain my problem in clear way.

Cached service class:

class testServiceImpl{

@CachePut(key = &quot;#result.id&quot;, condition = &quot;#result != null&quot;)
public List&lt;String&gt; create(String input) {
......
}

@CacheEvict(key=&quot;#id&quot;)
public void deleteById(Long id) {
.....
}

public void multiDelete(String input) {	
if(condition...){
  deleteById(2);  //Cache is not Evicted here i.e. the records are still present in getAll call but not in Database.
}else{
  create(input); //New Data is persisted in DB but the same has not been updated in Cache.
}	

@Transactional
@Cacheable
public Map&lt;Long, String&gt; getAll() {
 ...
}

I have tried using the below solutions as well but could not succeed.

//Create a new object of the same class and use the same. In this case, the data is not persisted in DB i.e. it is not deleting the data from DB.
     testServiceImpl testService;
                ...
              public void multiDelete(String input) {	
                if(condition...){
                  testService.deleteById(2);  
                }else{
              testService.create(input); 
            }

Can someone please help me to solve this issue ?

答案1

得分: 5

当您从您的服务调用方法时,实际上是通过代理进行调用的。自动连线的 bean 被包装在一个代理中,该代理拦截调用并仅为该方法处理缓存注解。

当您在内部进行调用时,直接在服务对象上进行调用,没有代理包装,缓存注解不会被处理。
【参见理解 AOP 代理】1

一个可行的替代方法是使用 AspectJ,它将直接将处理缓存注解的 Spring 切面编织到代码中,而不使用任何 Spring 代理,因此您可以调用内部方法并且缓存注解将如预期般被处理。

英文:

When you call a method from your service, you are actually calling it through a proxy. The autowired bean is wrapped in a proxy that intercepts the call and handles the cache annotations only for that method.

When you make the call internally, it is made directly on the service object, and without the proxy wrapper, the cache annotation is not processed.
See Understanding AOP Proxies

A working alternative is to use AspectJ that will weave the spring aspects that handle cache annotations directly into the code without using any Spring proxies, so you can call internal methods and cache annotation will be handled as expected.

huangapple
  • 本文由 发表于 2020年10月14日 20:47:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/64353609.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定