天天看點

從入門到精通:掌握 @Cacheable、@CachePut 和 @CacheEvict 注解

作者:java小悠

一、@Cacheable,@CachePut,@CacheEvict差別

當使用緩存時,Spring 提供了三個常用的注解:@Cacheable、@CachePut 和 @CacheEvict,它們的差別如下:

  1. @Cacheable 注解:
  2. 作用:将方法的傳回值緩存起來,以便下次相同的方法調用時可以直接從緩存中擷取結果。
  3. 使用場景:适用于讀取操作頻繁,但資料很少改變的場景。
  4. 示例代碼:
  5. kotlin複制代碼
  6. @Cacheable(value = "products", key = "#productId") public Product getProductById(Long productId) { // 從資料庫中擷取産品資訊 }
  7. 在上述示例中,使用 @Cacheable 注解将 getProductById 方法的傳回值緩存起來,緩存的名稱為 "products"。每次調用該方法時,如果緩存中存在對應的結果,就直接傳回緩存值;否則執行方法邏輯,并将結果放入緩存中。
  8. @CachePut 注解:
  9. 作用:将方法的傳回值更新到緩存中。
  10. 使用場景:适用于寫入或更新操作,需要将結果放入緩存并確定緩存的資料是最新的。
  11. 示例代碼:
  12. kotlin複制代碼
  13. @CachePut(value = "products", key = "#product.id") public Product saveProduct(Product product) { // 儲存産品資訊到資料庫 return product; }
  14. 在上述示例中,使用 @CachePut 注解将 saveProduct 方法的傳回值放入緩存中,緩存的名稱為 "products"。每次調用該方法時,無論緩存中是否存在對應的值,都會執行方法邏輯,并将結果更新到緩存中。
  15. @CacheEvict 注解:
  16. 作用:從緩存中移除一個或多個緩存項。
  17. 使用場景:适用于删除操作或資料更新後的緩存清理。
  18. 示例代碼:
  19. typescript複制代碼
  20. @CacheEvict(value = "products", key = "#productId") public void deleteProduct(Long productId) { // 從資料庫中删除産品資訊 }
  21. 在上述示例中,使用 @CacheEvict 注解将 deleteProduct 方法執行後,将緩存中指定 productId 的緩存項移除,緩存的名稱為 "products"。

二、進階使用

進階使用 @Cacheable、@CachePut 和 @CacheEvict 注解的一些注意事項和進階用法包括:

  1. 多緩存管理器支援:如果應用程式中使用了多個緩存管理器,可以使用 cacheManager 屬性指定具體的緩存管理器。
  2. kotlin複制代碼
  3. @Cacheable(value = "products", key = "#productId", cacheManager = "cacheManager1") public Product getProductById(Long productId) { // ... }
  4. 條件緩存:可以使用 SpEL 表達式在注解中定義條件,隻有滿足條件時才進行緩存操作。
  5. kotlin複制代碼
  6. @Cacheable(value = "products", key = "#productId", condition = "#productId > 0") public Product getProductById(Long productId) { // ... }
  7. 自定義緩存政策:通過實作 CacheResolver 接口或者使用 cacheResolver 屬性,可以自定義緩存的解析和管理邏輯。
  8. kotlin複制代碼
  9. @Cacheable(value = "products", key = "#productId", cacheResolver = "customCacheResolver") public Product getProductById(Long productId) { // ... }
  10. 緩存更新時機:可以使用 @CachePut 注解在方法執行後手動觸發緩存更新,而不是每次方法調用都更新緩存。
  11. kotlin複制代碼
  12. @CachePut(value = "products", key = "#product.id") public Product updateProduct(Product product) { // ... return product; }
  13. 緩存清除政策:使用 @CacheEvict 注解時,可以通過 beforeInvocation 屬性來控制清除緩存的時機,預設是在方法執行後清除緩存。
  14. typescript複制代碼
  15. @CacheEvict(value = "products", key = "#productId", beforeInvocation = true) public void deleteProduct(Long productId) { // ... }
  16. 緩存注解繼承:可以使用注解繼承方式,簡化對多個方法應用相同緩存注解的操作。
  17. less複制代碼
  18. @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() { // ... }
  19. 自定義緩存鍵生成政策:可以使用 keyGenerator 屬性指定自定義的緩存鍵生成器。
  20. kotlin複制代碼
  21. @Cacheable(value = "products", keyGenerator = "customKeyGenerator") public Product getProductById(Long productId) { // ... }
  22. SpEL 表達式使用:在注解的屬性值中可以使用 SpEL 表達式,動态計算緩存鍵、條件等。
  23. kotlin複制代碼
  24. @Cacheable(value = "products", key = "'product:' + #productId") public Product getProductById(Long productId) { // ... }
  25. 緩存注解的優先級:在方法上同時使用多個緩存注解時,它們的執行順序和優先級可以通過 @Order 注解進行控制。
  26. less複制代碼
  27. @Cacheable(value = "products", key = "#productId") @CachePut(value = "products", key = "#productId") @Order(1) public Product getProductById(Long productId) { // ... }
  28. 配置緩存過期時間:可以使用緩存管理器的配置來設定緩存的過期時間,或者在注解中通過 expiration 屬性指定緩存的過期時間。
  29. scala複制代碼
  30. @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) { // ... }
  31. 緩存條件判斷:可以使用 condition 屬性在注解中指定一個 SpEL 表達式,根據條件判斷是否執行緩存操作。
  32. kotlin複制代碼
  33. @Cacheable(value = "products", key = "#productId", condition = "#productId > 0") public Product getProductById(Long productId) { // ... }
  34. 同步緩存操作:使用 @CachePut 注解可以實作同步緩存操作,即先執行方法,然後更新緩存。
  35. kotlin複制代碼
  36. @CachePut(value = "products", key = "#product.id") public Product updateProduct(Product product) { // ... return product; }
  37. 緩存清除政策:@CacheEvict 注解可以用于清除緩存中的資料,可以通過 key 屬性指定要清除的緩存項。
  38. typescript複制代碼
  39. @CacheEvict(value = "products", key = "#productId") public void deleteProduct(Long productId) { // ... }
  40. 緩存注解順序:當一個方法上同時存在多個緩存注解時,可以使用 @CacheConfig 注解或 @Order 注解來控制注解的執行順序。
  41. less複制代碼
  42. @CacheConfig(cacheNames = "products") public class ProductRepository { @Cacheable(key = "#id") @CachePut(key = "#result.id") public Product getProductById(Long id) { // ... } }
  43. 使用 SpEL 表達式:可以在注解中使用 SpEL 表達式動态地生成緩存鍵。
  44. kotlin複制代碼
  45. @Cacheable(value = "products", key = "'product:' + #productId") public Product getProductById(Long productId) { // ... }
  46. 緩存與事務管理:在使用緩存注解時,需要注意與事務管理的互動。預設情況下,Spring 的事務管理會在方法執行前将緩存清空,以保證資料的一緻性。如果希望在事務送出後再執行緩存操作,可以使用 @CachePut 注解并将方法放在一個新的事務中。
  47. typescript複制代碼
  48. @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; }
  49. 多級緩存配置:可以配置多個級别的緩存,例如使用一級緩存作為本地緩存,二級緩存作為分布式緩存。可以通過 @CacheConfig 注解和 CacheManager 進行配置。
  50. less複制代碼
  51. @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) { // ... } }
  52. 緩存預熱:可以在應用啟動時,通過調用特定的方法來預先加載緩存資料,以提高系統的性能和響應速度。
  53. typescript複制代碼
  54. @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()); } } }
  55. 異步緩存操作:使用異步方式執行緩存操作,以減少對主線程的影響,提高系統的并發性能。
  56. less複制代碼
  57. @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)來指定要清除的特定緩存項。它還提供了一些屬性,如 allEntries 和 beforeInvocation,用于清除所有緩存項或在方法執行前清除緩存。

這些注解可以與不同的緩存提供程式內建,如 Spring Boot 預設的緩存提供程式 Caffeine、Ehcache、Redis 等。通過合理地使用這些注解,可以顯著提高應用程式的性能和響應速度。

原文連結:https://juejin.cn/post/7246279539985711162

繼續閱讀