掌握 @Cacheable、@CachePut 和 @CacheEvict 注解

本文详细介绍了Spring框架中@Cacheable、@CachePut和@CacheEvict注解的作用、使用场景、示例代码以及进阶特性,如多缓存管理器、缓存策略、异步操作等,帮助开发者提升应用程序性能和缓存管理效率。
摘要由CSDN通过智能技术生成

一、@Cacheable,@CachePut,@CacheEvict区别

当使用缓存时,Spring 提供了三个常用的注解:@Cacheable@CachePut@CacheEvict,它们的区别如下:

  1. @Cacheable 注解:
  • 作用:将方法的返回值缓存起来,以便下次相同的方法调用时可以直接从缓存中获取结果。

  • 使用场景:适用于读取操作频繁,但数据很少改变的场景。

  • 示例代码:

    @Cacheable(value = "products", key = "#productId")
    public Product getProductById(Long productId) {
        // 从数据库中获取产品信息
    }
    

在上述示例中,使用 @Cacheable 注解将 getProductById 方法的返回值缓存起来,缓存的名称为 “products”。每次调用该方法时,如果缓存中存在对应的结果,就直接返回缓存值;否则执行方法逻辑,并将结果放入缓存中。

  1. @CachePut 注解:
  • 作用:将方法的返回值更新到缓存中。

  • 使用场景:适用于写入或更新操作,需要将结果放入缓存并确保缓存的数据是最新的。

  • 示例代码:

@CachePut(value = "products", key = "#product.id")
        public Product saveProduct(Product product) {
            // 保存产品信息到数据库
            return product;
        }

在上述示例中,使用 @CachePut 注解将 saveProduct 方法的返回值放入缓存中,缓存的名称为 “products”。每次调用该方法时,无论缓存中是否存在对应的值,都会执行方法逻辑,并将结果更新到缓存中。

  1. @CacheEvict 注解:
  • 作用:从缓存中移除一个或多个缓存项。

  • 使用场景:适用于删除操作或数据更新后的缓存清理。

  • 示例代码:

@CacheEvict(value = "products", key = "#productId")
        public void deleteProduct(Long productId) {
            // 从数据库中删除产品信息
        }

在上述示例中,使用 @CacheEvict 注解将 deleteProduct 方法执行后,将缓存中指定 productId 的缓存项移除,缓存的名称为 “products”。

二、进阶使用

进阶使用 @Cacheable@CachePut@CacheEvict 注解的一些注意事项和高级用法包括:

  1. 多缓存管理器支持:如果应用程序中使用了多个缓存管理器,可以使用 cacheManager 属性指定具体的缓存管理器。
@Cacheable(value = "products", key = "#productId", cacheManager = "cacheManager1")
    public Product getProductById(Long productId) {
        // ...
    }
  1. 条件缓存:可以使用 SpEL 表达式在注解中定义条件,只有满足条件时才进行缓存操作。
 @Cacheable(value = "products", key = "#productId", condition = "#productId > 0")
    public Product getProductById(Long productId) {
        // ...
    }
  1. 自定义缓存策略:通过实现 CacheResolver 接口或者使用 cacheResolver 属性,可以自定义缓存的解析和管理逻辑。
@Cacheable(value = "products", key = "#productId", cacheResolver = "customCacheResolver")
    public Product getProductById(Long productId) {
        // ...
    }
  1. 缓存更新时机:可以使用 @CachePut 注解在方法执行后手动触发缓存更新,而不是每次方法调用都更新缓存。
    @CachePut(value = "products", key = "#product.id")
    public Product updateProduct(Product product) {
        // ...
        return product;
    }
  1. 缓存清除策略:使用 @CacheEvict 注解时,可以通过 beforeInvocation 属性来控制清除缓存的时机,默认是在方法执行后清除缓存。
    @CacheEvict(value = "products", key = "#productId", beforeInvocation = true)
    public void deleteProduct(Long productId) {
        // ...
    }
  1. 缓存注解继承:可以使用注解继承方式,简化对多个方法应用相同缓存注解的操作。
@Inherited
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Cacheable(value = "products", key = "#productId")
    public @interface CachedProduct {
        // ...
    }
    @CachedProduct
    public Product getProductById(Long productId) {
        // ...
    }
    @CachedProduct
    public List<Product> getAllProducts() {
        // ...
    }
  1. 自定义缓存键生成策略:可以使用 keyGenerator 属性指定自定义的缓存键生成器。
@Cacheable(value = "products", keyGenerator = "customKeyGenerator")
    public Product getProductById(Long productId) {
        // ...
    }
  1. SpEL 表达式使用:在注解的属性值中可以使用 SpEL 表达式,动态计算缓存键、条件等。
@Cacheable(value = "products", key = "'product:' + #productId")
    public Product getProductById(Long productId) {
        // ...
    }
  1. 缓存注解的优先级:在方法上同时使用多个缓存注解时,它们的执行顺序和优先级可以通过 @Order 注解进行控制。
@Cacheable(value = "products", key = "#productId")
    @CachePut(value = "products", key = "#productId")
    @Order(1)
    public Product getProductById(Long productId) {
        // ...
    }
  1. 配置缓存过期时间:可以使用缓存管理器的配置来设置缓存的过期时间,或者在注解中通过 expiration 属性指定缓存的过期时间。
@Configuration
    @EnableCaching
    public class CacheConfig extends CachingConfigurerSupport {
        // ...
        @Override
        public CacheManager cacheManager() {
            SimpleCacheManager cacheManager = new SimpleCacheManager();
            // 设置缓存过期时间
            cacheManager.setCaches(Arrays.asList(
                new ConcurrentMapCache("products", getExpirationDuration(30)),
                // ...
            ));
            return cacheManager;
        }
        private Duration getExpirationDuration(int minutes) {
            return Duration.ofMinutes(minutes);
        }
    }
    @Cacheable(value = "products", key = "#productId", expiration = 10)
    public Product getProductById(Long productId) {
        // ...
    }
  1. 缓存条件判断:可以使用 condition 属性在注解中指定一个 SpEL 表达式,根据条件判断是否执行缓存操作。
 @Cacheable(value = "products", key = "#productId", condition = "#productId > 0")
    public Product getProductById(Long productId) {
        // ...
    }
  1. 同步缓存操作:使用 @CachePut 注解可以实现同步缓存操作,即先执行方法,然后更新缓存。
@CachePut(value = "products", key = "#product.id")
    public Product updateProduct(Product product) {
        // ...
        return product;
    }
  1. 缓存清除策略:@CacheEvict 注解可以用于清除缓存中的数据,可以通过 key 属性指定要清除的缓存项。
@CacheEvict(value = "products", key = "#productId")
    public void deleteProduct(Long productId) {
        // ...
    }
  1. 缓存注解顺序:当一个方法上同时存在多个缓存注解时,可以使用 @CacheConfig 注解或 @Order 注解来控制注解的执行顺序。
@CacheConfig(cacheNames = "products")
    public class ProductRepository {
        @Cacheable(key = "#id")
        @CachePut(key = "#result.id")
        public Product getProductById(Long id) {
            // ...
        }
    }
  1. 使用 SpEL 表达式:可以在注解中使用 SpEL 表达式动态地生成缓存键。
```
@Cacheable(value = "products", key = "'product:' + #productId")
public Product getProductById(Long productId) {
    // ...
}
```
  1. 缓存与事务管理:在使用缓存注解时,需要注意与事务管理的交互。默认情况下,Spring 的事务管理会在方法执行前将缓存清空,以保证数据的一致性。如果希望在事务提交后再执行缓存操作,可以使用 @CachePut 注解并将方法放在一个新的事务中。
```
@Transactional
public void updateProduct(Product product) {
    // 更新数据库中的数据
    // ...
    // 手动执行缓存操作
    updateProductCache(product);
}
@CachePut(value = "products", key = "#product.id")
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Product updateProductCache(Product product) {
    // 更新缓存中的数据
    // ...
    return product;
}
```
  1. 多级缓存配置:可以配置多个级别的缓存,例如使用一级缓存作为本地缓存,二级缓存作为分布式缓存。可以通过 @CacheConfig 注解和 CacheManager 进行配置。
```
@CacheConfig(cacheNames = "products")
public class ProductRepository {
    @Autowired
    private CacheManager cacheManager;
    @Cacheable(key = "#id", cacheManager = "localCacheManager")
    public Product getProductById(Long id) {
        // ...
    }
    @Cacheable(key = "#id", cacheManager = "distributedCacheManager")
    public Product getProductByIdFromDistributedCache(Long id) {
        // ...
    }
}
```
  1. 缓存预热:可以在应用启动时,通过调用特定的方法来预先加载缓存数据,以提高系统的性能和响应速度。
```
@Component
public class CachePreloader {
    @Autowired
    private ProductRepository productRepository;
    @PostConstruct
    public void preloadCache() {
        List<Product> products = productRepository.getAllProducts();
        for (Product product : products) {
            productRepository.getProductById(product.getId());
        }
    }
}
```
  1. 异步缓存操作:使用异步方式执行缓存操作,以减少对主线程的影响,提高系统的并发性能。
```
@CachePut(value = "products", key = "#product.id")
@Async
public CompletableFuture<Product> updateProductAsync(Product product) {
    // ...
    return CompletableFuture.completedFuture(product);
}
```

以上是一些进阶用法和注意事项,它们可以帮助你更好地使用 @Cacheable@CachePut@CacheEvict 注解来管理缓存,并根据具体的业务需求和场景进行优化和配置。请根据实际情况选择合适的用法,并结合缓存框架和缓存管理器的文档进行深入研究和调整。

三、总结

  1. @Cacheable 注解用于指示方法的结果应该被缓存,以提高后续对相同输入参数调用的性能。它会首先检查缓存中是否存在结果,如果存在,则直接返回缓存中的值;如果不存在,则执行方法并将结果存入缓存。可以通过设置缓存的键(key)来区分不同的缓存项。

  2. @CachePut 注解用于指示方法的结果应该被缓存,但它每次都会执行方法并将结果存入缓存,不会像 @Cacheable 那样检查缓存中是否已存在结果。它常用于更新缓存中的数据,确保缓存的数据与数据库或其他数据源保持同步。

  3. @CacheEvict 注解用于指示方法执行后应清除缓存中的某些项。可以通过设置缓存的键(key)来指定要清除的特定缓存项。它还提供了一些属性,如 allEntriesbeforeInvocation,用于清除所有缓存项或在方法执行前清除缓存。

这些注解可以与不同的缓存提供程序集成,如 Spring Boot 默认的缓存提供程序 Caffeine、Ehcache、Redis 等。通过合理地使用这些注解,可以显著提高应用程序的性能和响应速度。

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架通过Spring Cache提供了一套强大的缓存体系,可以轻松地实现缓存数据,提高应用程序的性能。Spring框架提供了三个主要的注解来实现缓存:@Cacheable、@CachePut和@CacheEvict。 @Cacheable注解用于将方法的结果缓存起来,以便在下次请求时,如果参数相同,则可以直接从缓存中获取结果,而不需要重新计算。该注解适用于如果计算结果比较耗时,或者需要从数据库或其他外部资源中提取数据的情况。 @CachePut注解用于更新缓存中的数据。它与@Cacheable注解类似,但不同的是,它总是更新缓存数据,而不管缓存中是否已经存在该key的值。所以,可以使用这个注解来更新缓存中的数据。 @CacheEvict注解用于从缓存中删除数据。它在需要删除缓存数据的情况下使用。它可以删除指定的key对应的缓存,也可以清空所有缓存数据。 这三个注解都有一个可选参数Named:如果指定了该参数,则缓存将使用指定的名称使用。如果未指定,则使用默认的名称。可以使用不同名称的缓存来存储不同类型的数据,并使用不同的缓存策略来控制它们的存储方式。 除了Spring自带的缓存提供者之外,还可以使用其他的缓存提供者,如EhcacheRedis、Memcached等等。在使用缓存时,需要注意的是,不同的缓存提供者之间可能会有不同的限制和性能差异。因此,必须根据实际情况选择最适合的缓存提供者和缓存策略,以获取最好的性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值