当前位置: 首页 > 知识库问答 >
问题:

缓存 - Spring Cache中@CachePut的疑问?

谭锐藻
2024-10-07

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

共有2个答案

濮彬
2024-10-07
这个缓存有什么意义呢?

@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
}
荀辰钊
2024-10-07

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

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;
}
 类似资料:
  • 问题内容: 我的任务是利用SpringCache作为我们的一项服务,以减少数据库查找的次数。在测试实现时,我注意到一些可缓存操作通过日志语句多次调用。调查显示,如果在可缓存的方法中调用了可缓存的操作,则嵌套操作根本不会被缓存。因此,嵌套操作的后续调用将导致进一步的查找。 下面列出了描述问题的简单单元测试: 这两种方法的实际工作对于测试用例本身并不重要,因为仅应测试缓存。 我以某种方式理解了为什么不

  • 我的@cacheable方法有下一个签名: 该过滤器使用reporisoty,以limit作为分页参数,返回实体列表。我正在尝试在向系统添加实体时更新缓存: java.lang.ClassCastException:不能将com.java.domain.Entity强制转换为java.util.List

  • 我正在学习Spring Boot缓存,以便在我们组织的项目中应用这个概念,我制作了一个名为Emploe Cache的示例项目。我的控制器和服务组件中有四个方法insert、update、get和getall,对于insert和get,工作得很好。现在我第一次调用,然后它从数据库中提取数据。之后,我尝试使用进行更新,它更新数据库中的值,并且再次调用,但它没有从缓存返回更新的值。我还参考了的文档。我也

  • 本文向大家介绍浅谈SpringCache与redis集成实现缓存解决方案,包括了浅谈SpringCache与redis集成实现缓存解决方案的使用技巧和注意事项,需要的朋友参考一下 缓存可以说是加速服务响应速度的一种非常有效并且简单的方式。在缓存领域,有很多知名的框架,如EhCache 、Guava、HazelCast等。Redis作为key-value型数据库,由于他的这一特性,Redis也成为一

  • 问题内容: 我想在Redis中实现绝对缓存和滑动缓存。没有人有任何资源链接,这将是有帮助的 问题答案: Redis已经为此提供了许多命令: 到期:设置密钥超时。 期望值:与以前相同,但是需要一个绝对的Unix时间戳(自1970年1月1日以来的秒数)。 TTL:返回具有超时功能的键的剩余生存时间 您必须了解有关Redis过期的重要一件事:仅当使用SET或GETSET移除或覆盖键时,才会清除超时值。所