Spring Cache中@CachePut的疑问?

如题,查阅资料得知@CachePut的作用是无论是否存在缓存,否会把方法的返回值更新入缓存,作用是更新缓存,适用于update操作。
假如我写个方法:
public int updateUser(User user){},int表示0,1,那这个缓存有什么意义呢?而且执行了update后,@Cacheable的数据会同步更新吗?不更新数据不是就不对了吗?
实际项目中update了以后到底应该怎么做呢??我感觉应该把缓存全部清空才对啊!

阅读 1.3k
2 个回答

一开始你的思路就是错误的,这里对应了两种设计方案,也要看你的具体需求

1.以缓存中的数据为准

这种情下,一般来说,用户量非常大,数据库不能接受缓存击穿

在更新/删除完成后,应该将数据更新到缓存,而不是删除缓存

这才是@CachePut应该做的事,假如你更新完删除了缓存,接下来大批量的查询请求来了,先查询缓存,缓存没有,批量请求打入库中 ,缓存层没有任何意义,这一瞬间,数据库可能就奔溃了,会造成重大事故。

解决方案:

更新后,事务提交,同时向缓存中写入更新的数据
删除后,事务提交,同时向缓存中写入null数据(null也是数据,代表没有,不然还是会请求打到数据库中)

2.以数据库中的数据为准

适合冷门数据,用户不会在同一时间访问,数据比较离散,只是需要减轻多次查询的负担

在更新/删除完成后,可以直接将缓存删除

这种时候应该是用@CacheEvict,直接删除缓存,下次请求到来,会先查询缓存,缓存没有,再次查询库中,然后将数据写入缓存,后面就是缓存查询的结果,但是也要注意NULL值是否写入缓存,否则库中无数据,每次都查库,高频查询会引起奔溃。

最后讲下@CachePut

将方法的返回值作为缓存的结果存入到指定的key中(如果缓存已经存在,则覆盖)

你这个方法返回int值,说明你们的架构师就是个水货,update语句的返回值表示命中的函数,仅在持久层使用就可以了,对外暴漏这样的返回值有什么意义呢?正统的写法


private final UserMapper userMapper;

@CachePut(value = "users", key = "#user.id" )
public User updateUser(User user){
    int row = userMapper.updateByPrimaryKey(user);
    // 1 是命中了一行,已更新,0是未命中,或者更新的所有字段与原来的字段值一致(应该有拦截器处理update_time和version等公共字段,避免返回0的情况)
    if(row != 1){
        throw new BizException("update fail !");
    }

    return user;
}
这个缓存有什么意义呢?

@CachePut可以确保每次调用方法都会执行该方法,并将返回值更新到缓存中。即使返回值是0或1,缓存依然可以存储完整的对象或状态信息,确保后续读取时能获取到最新的数据。

执行了update后,@Cacheable的数据会同步更新吗?

@Cacheable注解不会自动同步更新缓存。它是用来在缓存中查找数据,如果找到则直接返回,而不执行方法。如果想在更新数据后缓存也更新,需要在更新方法中使用@CachePut,或使用@CacheEvict清除缓存,方便下次调用时重新加载最新数据。
在执行更新操作后,使用@CachePut来更新缓存,或使用@CacheEvict清除旧缓存,确保下一次读取能够获取最新数据。

实际项目中update了以后到底应该怎么做呢?

使用@CachePut更新缓存中的数据;
如果要清除旧的缓存,使用@CacheEvict

@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
    ...
    return user;
}

@CacheEvict(value = "users", key = "#user.id")
public void evictUserFromCache(User user) {
    ... // clear user cache
}
宣传栏