Повторно использовать ключ кэша кофеина

Я реализовал cache, используя caffeine. Я хочу, чтобы срок его действия истекал через 1 day, и это работает нормально. Проблема в том, что если я попытаюсь получить данные из cache, используя модифицированный запрос (измененный с точки зрения значений параметров), я всегда получаю одни и те же результаты. Я хочу получить те же результаты, только если я выполнил запрос с одинаковыми значениями параметров (например, с тем же диапазоном дат). Насколько я понимаю, мне не следует повторно использовать один и тот же cache-key, но я не уверен, как это сделать. Это реализация:

@Service
public class SomeServiceImpl implements SomeService {
  private static final String CACHE_KEY = "some-key";
  private Cache<String, List<SomeVO>> someCache;



  public RecentHighestSlotWinsServiceImpl() {

    someCache= Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.DAYS).build();
  }

  @Override
  public List<SomeVO> checkCacheForData(Instant startDate, Instant endDate) {

  List<SomeVO> someList= someCache.getIfPresent(CACHE_KEY);
  if (someList!= null) {
      return someList;
  } else {
      log.info("Loading from DB ");
      List<SomeVO> templateResult= getData(startDate, endDate);
      if (templateResult.isSuccessAndNotNull()) {
          someCache.put(CACHE_KEY, Objects.requireNonNull(templateResult.getData()));
      }
      return templateResult;
  }
}

person C96    schedule 01.07.2020    source источник
comment
Предположительно, вместо Cache с ключом String вы должны кэшировать на основе объекта с правильно реализованным equals и hashCode, который содержит startDate и endDate.   -  person Louis Wasserman    schedule 01.07.2020
comment
Не могли бы вы опубликовать или указать пример? Я не могу найти хороший источник в Интернете   -  person C96    schedule 01.07.2020
comment
Вы знаете, как создать класс, который содержит два момента?   -  person Louis Wasserman    schedule 01.07.2020
comment
Да, простой POJO.   -  person C96    schedule 01.07.2020
comment
расширение от авторов java.time включает Интервал. Обратите внимание, что ваш собственный POJO должен будет реализовать equals и hashCode.   -  person Ben Manes    schedule 01.07.2020
comment
@Louis на самом деле нет, я не знаю, как создать этот класс   -  person C96    schedule 01.07.2020


Ответы (1)


Пара способов справиться с этим:

  1. Как упомянул @Louis Wasserman, сделайте что-то вроде этого:
import java.time.Instant;
import java.util.Objects;

public class CacheKey {
  private Instant startDate;
  private Instant endDate;

  public CacheKey() {
  }

  public CacheKey(Instant startDate, Instant endDate) {
    this.startDate = startDate;
    this.endDate = endDate;
  }

  public Instant getStartDate() {
    return startDate;
  }

  public void setStartDate(Instant startDate) {
    this.startDate = startDate;
  }

  public Instant getEndDate() {
    return endDate;
  }

  public void setEndDate(Instant endDate) {
    this.endDate = endDate;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o)
      return true;
    if (o == null || getClass() != o.getClass())
      return false;
    CacheKey cacheKey = (CacheKey) o;
    return Objects.equals(startDate, cacheKey.startDate) &&
        Objects.equals(endDate, cacheKey.endDate);
  }

  @Override
  public int hashCode() {
    return Objects.hash(startDate, endDate);
  }
}

и в вашем методе checkCacheForData используйте:

@Service
public class SomeServiceImpl implements SomeService {
  private Cache<CacheKey, List<SomeVO>> someCache;



  public RecentHighestSlotWinsServiceImpl() {

    someCache= Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.DAYS).build();
  }

  @Override
  public List<SomeVO> checkCacheForData(Instant startDate, Instant endDate) {

  List<SomeVO> someList= someCache.getIfPresent(new CacheKey(startDate,endDate));
  if (someList!= null) {
      return someList;
  } else {
      log.info("Loading from DB ");
      List<SomeVO> templateResult= getData(startDate, endDate);
      if (templateResult.isSuccessAndNotNull()) {
          someCache.put(new CacheKey(startDate,endDate), Objects.requireNonNull(templateResult.getData()));
      }
      return templateResult;
  }
}
  1. Вместо того, чтобы иметь отдельный объект, вы можете объединить строковое представление даты начала и даты окончания и использовать его в качестве ключа кэша.
@Service
public class SomeServiceImpl implements SomeService {
  private Cache<String, List<SomeVO>> someCache;



  public RecentHighestSlotWinsServiceImpl() {

    someCache= Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.DAYS).build();
  }

  @Override
  public List<SomeVO> checkCacheForData(Instant startDate, Instant endDate) {

String cacheKey = startDate.toString() + endDate.toString();
  List<SomeVO> someList= someCache.getIfPresent(cacheKey);
  if (someList!= null) {
      return someList;
  } else {
      log.info("Loading from DB ");
      List<SomeVO> templateResult= getData(startDate, endDate);
      if (templateResult.isSuccessAndNotNull()) {
          someCache.put(cacheKey, Objects.requireNonNull(templateResult.getData()));
      }
      return templateResult;
  }
}
person Abhinaba Chakraborty    schedule 01.07.2020
comment
Это выглядит великолепно, но я бы рекомендовал удалить сеттеры из CacheKey. Ключи кэша никогда не должны быть изменены! - person Louis Wasserman; 01.07.2020