Spring Boot 缓存注释在使用 Redis 进行缓存的应用程序中的作用是什么?

时间:2021-04-08 12:09:02

标签: java spring caching redis spring-data-redis

我在 Spring Boot 应用程序中使用 Redis 作为内存数据存储,用于缓存目的。目前,我已经为需要缓存的实体实现了具有基本 CRUD 功能的 Redis 支持 [场景 1]。但突然间我发现有很多资源使用额外的 Spring Boot 缓存注释(如 @Cachable @CahceEvict )来实现 Redis [场景 2] 的缓存。我监视到,当我们开始在 find(params) 等操作中使用这些注释时,只有第一个方法调用会转到 Redis。从第二种方法开始,Redis 不会被击中。所以根据我的观察,我认为,Spring boot 维护了一个单独的缓存。但我的问题是我们已经在使用 Redis 作为我们的缓存。那么阻止第二个 Redis 数据存储命中并维护另一个缓存有什么好处。我的意思是 Redis 已经在 RAM 中并且它具有很强的缓存能力。为什么我们需要维护两个缓存?有这种机制有什么好处吗,或者只实现Redis就足够了?。

场景 1:

public class RestController{

@GetMapping("/{id}")
public Product findProductById(@PathVariable int Id){
           return dao.findProductById(id);
}


}
@Repository
public class ProductDao {

    public static final String HASH_KEY = "Product";

    @Autowired
    private RedisTemplate template;
  

    public Product findProductById(int id){
        return (Product) template.opsForHash().get(HASH_KEY,id);
    }

}

场景 2:

public class RestController{

@GetMapping("/{id}")
@Cachable(key = "#id" ,value="Product")
public Product findProductById(@PathVariable int Id){
           return dao.findProductById(id);
}

}
@Repository
public class ProductDao {

    public static final String HASH_KEY = "Product";

    @Autowired
    private RedisTemplate template;
  

    public Product findProductById(int id){
        System.out.println("called findProductById() from DB");//Here only for the first time method will be called
        return (Product) template.opsForHash().get(HASH_KEY,id);
    }

}

References for Scenario 1 implementation

References for Scenario 2 implementation

1 个答案:

答案 0 :(得分:3)

Spring Cache abstraction 提供了一个缓存抽象层,您可以对其进行配置以支持不同的、可插入的、底层缓存机制,Redis through Spring Data 等。

您正在使用 Redis 作为实际的持久性机制。因此,您可能不需要任何缓存,并且由于 Redis 数据库的内存性质,场景 1 可能是合适的。

话虽如此,请考虑不同的观点。

例如,让我们考虑一个后端,它使用持久层和底层非内存数据库、关系型或其他类型的 NoSQL。

这是 Spring Cache、@Cacheable 和其他相关注释的完美用例,可有效缓存您的结果。

而且,Redis 如何解决这个难题?因为您 configure Spring 使用 Redis 作为实际的 cache manager。例如:

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
    return RedisCacheManager.create(connectionFactory);
}

在幕后,RedisCacheManager 将提供必要的机制,以根据应用程序缓存的要求透明地写入和读取 Redis。

从这个新观点来看,场景 2 具有上述差异,是可供选择的场景,实际上是您在构建企业应用程序时通常会发现的常见场景。

无论如何,您的问题中描述的场景 2,我的意思是,除了 Spring Cache 之外,直接使用 Redis 作为持久化机制,如果您正在尝试,也可以适用:

  • 减少针对 Redis 执行的请求数量以及相关成本。如果您在云提供商中使用 Redis(或类似 Redis 的服务,例如 GCP Memorystore),这可能尤其重要。
  • 尽管 Redis 足够快,但您可以使用缓存将结果存储在运行应用程序的机器的本地 RAM 中,以提高性能,就像使用任何其他数据库系统一样。
  • 或者因为您需要以某种特定方式与 Redis 交互。

如果您仅将 Redis 用于缓存并且不需要任何特定的东西,则可能最好通过 Spring Cache 抽象而不是手动执行缓存操作来使用它:它不会提供性能优势,但您会获得多项优势,例如结构良好的缓存框架、一组有用的注释以及可移植性/可用性,因为您可以仅在需要时使用不同的配置来切换缓存实现,例如用于测试或本地开发。