我应该如何使用 Spring Boot 实现缓存以进行 crud 操作

How should I implement caching using Spring Boot for crud operations

我是实施 spring 缓存的新手,在选择正确的缓存使用方式时遇到了问题。下面以用户服务中的一些方法为例:

  @NotNull
  @Cacheable("usersCache")
  Optional<User> getUser(@NotNull Long id, @NotNull CompanyDetails companyDetails);
  
  @NotNull
  @Cacheable("usersCache")
  Pageable<User> getUsers(@NotNull CompanyDetails companyDetails, @NotNull Long offset, @NotNull Long limit);

  @NotNull
  @Cacheable("usersCache")
  List<User> getUsers(@NotNull CompanyDetails companyDetails);
  
  @NotNull
  @Cacheable("usersCache")
  Optional<User> getUser(@NotNull String key, @NotNull CompanyDetails companyDetails);
  
  
  @NotNull
  Optional<UserDetails> createUser(@NotNull final UserRequest request, @NotNull CompanyDetails companyDetails);
  
  @NotNull
  Optional<User> updateUser(@NotNull final UserRequest request, @NotNull CompanyDetails companyDetails);
  
  @NotNull
  Optional<User> deleteUser(@NotNull final Long id, @NotNull CompanyDetails companyDetails); 

由于键是默认根据参数值生成的,getUser(@NotNull String key)getUser(@NotNull Long id) 对于同一用户在缓存中会有不同的条目。这是我面临的障碍之一,因为这意味着我可能因此有很多重复的条目。

第二个问题是我有两种 getUsers 方法来获取用户,一种有分页,另一种没有。这两个方法将在缓存中有自己的条目,这意味着会有很多重复,更糟糕的是,对于每个不同的偏移量和限制组合,缓存中都会有一个条目,这会创建很多重复。

现在有创建、更新和删除方法。鉴于方法更新、删除和 getUser 方法将直接将 id 作为参数值或作为 UserRequest 对象中的字段,我不应该将此 id 与其他参数一起用作键的一部分吗?

此外,请考虑以下情况:

@NotNull
  Optional<UserDetails> createUser(@NotNull final UserRequest request, @NotNull CompanyDetails companyDetails);

此处添加了用户,每当添加新用户时,我应该刷新整个 usersCache 还是应该等待 TTL 清除缓存?

鉴于每个方法的缓存中添加了大量重复项,因为它们具有不同的参数,是否有一种有效的方法可以遵循。我应该使用 spring 生成的默认密钥,还是应该遵循任何特定的方法来指定密钥?

您将同一个缓存与不同的密钥类型混合在一起。我建议使用密钥生成器,例如

@Cacheable(cacheNames = "mycache", key = "#object.id")
public Object myMethod( Object object )

否则,它将不起作用,因为 equals-method 永远不会 return 对不同的类型为真,例如 CompanyDetailsSimpleKey

如上所述,您不能对不同的 return 类型函数使用相同的缓存名称。

您可以定义自定义缓存键来解决您的问题。

我会建议类似的东西:

  @NotNull
  @Cacheable(cacheNames = {"usersCache"}, key = "{#id}")
  Optional<User> getUser(@NotNull Long id, @NotNull CompanyDetails companyDetails);

  @NotNull
  @Cacheable(cacheNames = {"usersCache"}, key = "{#key}")
  Optional<User> getUser(@NotNull String key, @NotNull CompanyDetails companyDetails);

  @NotNull
  @Cacheable(cacheNames = {"pageableUsersCache"}, key = "{#companyDetails.id,#offset,#limit}")
  Pageable<User> getUsers(@NotNull CompanyDetails companyDetails, @NotNull Long offset, @NotNull Long limit);

  @NotNull
  @Cacheable(cacheNames = {"userListCache"}, key = "{#companyDetails.id}")
  List<User> getUsers(@NotNull CompanyDetails companyDetails);

  @NotNull
  Optional<UserDetails> createUser(@NotNull final UserRequest request,      @NotNull CompanyDetails companyDetails);
  
 /**
   * If you want to cache user when it is created then you need to change the signature of your function to 
   * return Optional<User>
   */
  @NotNull
  @CachePut(cacheNames = {"usersCache"}, key = "{#request.id}")
  Optional<User> createUser(@NotNull final UserRequest request, @NotNull CompanyDetails companyDetails);

  @NotNull
  // CachePut will update the cache for defined key and you don't have to manage eviction
  @CachePut(cacheNames = {"usersCache"}, key = "{#request.id}")
  @CacheEvict(cacheNames = {"userListCache"}, key = "{#companyDetails.id}")
  Optional<User> updateUser(@NotNull final UserRequest request, @NotNull CompanyDetails companyDetails);

  @NotNull
  // This should evict both the caches as listed based on the defined key
  @Caching(evict = {
          @CacheEvict(cacheNames = {"usersCache"}, key = "{#id}"),
          @CacheEvict(cacheNames = {"userListCache"}, key = "{#companyDetails.id}")})
  Optional<User> deleteUser(@NotNull final Long id, @NotNull CompanyDetails companyDetails);

对于pageableUsersCache,仅在用户删除或更新时逐出缓存并不容易,因为您需要了解完整的密钥才能删除它。或者您可以定义自定义注释,它可以按“companyDetails.id*”等模式删除键。 否则,您可以使用 :

删除 pageableUsersCache 的所有缓存条目

  @Caching(evict = {
          @CacheEvict(cacheNames = {"usersCache"}, key = "{#id}"),
          @CacheEvict(cacheNames = {"userListCache"}, key = "{#companyDetails.id}"),
          @CacheEvict(cacheNames = {"pageableUsersCache"}, allEntries = true)})
  Optional<User> deleteUser(@NotNull final Long id, @NotNull CompanyDetails companyDetails);