带有 Spring Boot 的咖啡因:如何缓存对象列表、使用 id 更新/删除对象以及将新对象插入缓存

我是 Caffeine 和 Spring Boot 的新手。我正在尝试找到缓存对象列表的解决方案。数据库事务需要 3 秒来加载列表,所以我希望使用 Caffeine 缓存结果集。要单独缓存每个项目,我遵循以下方法,但它似乎不起作用。

public List<Item> getAllItemsOnStartUp() {
            allItemsList = repo.getAllItems();
            for (Item item : allItemsList) {
                staticItem = item;
                getItem(item.getItmsId());
            }

        return allItemsList;
    }

    @CachePut(value = "allItems", key = "#itmsId")
    public Item getItem(BigInteger itmsId) {
        return item;
    }

@Override
@Cacheable(value = "allItems")
    public List<Item> getAllItems() {

        allItemsList = repo.getAllItems();
        return allItemsList;
    }

@Override
    @Transactional
    @CachePut(value = "allItems", key="#a0.itmsId")
    public Item insertItem(Item item) {
      Item savedItem = rRepo.save(item);
      return savedItem;
    }

当服务器启动时, getAllItemsOnStartUp() 必须运行并填充缓存。应用程序调用 getAllItems() 来检索列表,预计会在此处使用缓存,但每次应用程序从数据库获取数据需要 3 秒。

stack overflow Caffeine with Spring boot: How to cache a list of objects, update/delete an object using id and insert new objects to cache
原文答案

答案:

作者头像

我今天看到了这个帖子,但无论如何我都会回答。也许它可以帮助别人。

Spring-boot 默认使用 CaffeineCache 来缓存服务调用,使用起来非常简单。您只需要使用@Cacheable 注释您的服务方法。下面的示例将用户权限缓存在名为“sso-users-cache”的缓存中(因为我不想一直调用该服务来检查用户的权限),使用公司名称创建一个条目(系统是多company) 和 userId,除非该方法返回错误(请记住:如果您没有分句除非,您甚至可以缓存服务的错误)。

    @Cacheable(cacheNames = ["sso-users-cache"], key = "#company.concat('-sso-user-').concat(#userId)", unless = "#result instanceof T(com.github.michaelbull.result.Err)")
fun fetchActionsByOrganizationAndUser(company: String, userId: String): Result<Set<String>, String> {
    val response = Unirest
        .get(getUserPermitionsUrl(company = company, userId = userId))
        .header("Content-Type", "application/json")
        .asString()
        .ifFailure {
            logger.error("SSO Error: Get user permissions failed: context: $company : userId: $userId")
        }

    return if(response.isSuccess) {
        Ok(serializeUtil.asCollection(response.body, String::class.java).toSet())
    } else {
        Err("SSO Error: Get user permissions failed: context: $company : userId: $userId"")
    }
}

参数 cacheNames 定义缓存中的条目,而键将告诉缓存中条目的名称(使用它是因为用户具有不同的权限并且他们需要缓存中的不同条目。

如果我的方法返回错误,参数 unless 告诉缓存不要缓存(非常重要!)

关于更新缓存信息,没有必要。您需要的是在用户权限更改时使缓存信息无效。例如,下面的方法为用户添加新权限,我需要使特定用户的缓存无效(清除):

@CacheEvict(cacheNames = ["sso-user-actions-cache"], key = "#company.concat('-user-actions-').concat(#userId)")
fun addPermissionToUser(company: String, userId: String, permission: String) {
    Unirest
        .put(addUserPermitionsUrl(company = company, userId = userId, permission = permission))
        .header("Content-Type", "application/json")
        .asEmpty()
}

再说一遍:使用属性键很重要,因为我只想清除特定用户的条目!!!否则,您将清除整个权限缓存(针对所有用户)

在@CacheEvict 之后,下一个检查用户权限的调用,spring 将意识到用户在缓存上没有条目,并将调用服务并缓存返回。而已。