我应该如何使用 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 对不同的类型为真,例如 CompanyDetails
和 SimpleKey
。
如上所述,您不能对不同的 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);
我是实施 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 对不同的类型为真,例如 CompanyDetails
和 SimpleKey
。
如上所述,您不能对不同的 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);