ExpireAfterWrite, похоже, не работает

Я пытаюсь использовать Google Guache Cache и просто тестирую его с помощью expireAfterWrite с интервалом в 1 минуту. В приложении, над которым я работаю, сотни пользователей. Таким образом, я понимаю, что когда первый человек получает доступ к кешу, мы заполняем его из базы данных, а затем должен начаться обратный отсчет. Теперь, когда кеш заполнен. Мы всегда будем получать его из кэша в течение этого минутного периода. Через одну минуту он истечет, и мы снова получим его из базы данных.

Тем не менее, похоже, что каждый раз, когда я обращаюсь к кешу в течение одной минуты, таймер сбрасывается. Это почему? Если я не получаю доступ к кешу в течение одной минуты, кеш истекает и работает нормально.

Код:

 Cache<Long, List<someObj>> cacheMap = CacheBuilder.newBuilder().maximumSize(maxSize).expireAfterWrite(maxTime, TimeUnit.MINUTES).removalListener(new RemovalListener<Long, List<someObj>>() {
    public void onRemoval(RemovalNotification<Long, List<someObj>> notification) {
        if (notification.getCause() == RemovalCause.EXPIRED) {
            logger.info("Value " + notification.getValue() + " has been expired");
        } else {
            logger.info("Just removed for some reason");
        }
    }
}).build();

...
//Convert to ConcurrentHashMap
cacheMap = someCache.asMap();

...


public List<someObj> getAllData(final Long orgId, final User user) {
    // Get requests from cache
    List<Request> cacheList = overdueSlaMap.get(orgId);

    // Fill cached requests if null
    cacheList = fillCacheIfNecessary(orgId, cacheList, overdueSlaMap);  

    return cacheList;
}

//Strategy for reading and writing to cache
//This method is fine. On first load, cache is empty so we fill it from database. Wait one minute, value expires and cache is empty again so we get from cache. 
//However, everytime I refresh the page the one minute timer starts again. Surely, the one minute timer within the Guava Cache should not refresh regardless of how many times I access the cache within that one minute period. 
 private List<someObj> fillCacheIfNecessary(List<someObj> cacheList, ConcurrentMap<Long, List<someObj>> cacheMap) {

        // If the cache is empty then we will try to fill it from the database.
        if (cacheList == null) {
            logger.info("populating cache");
            List<someObj> objList = new ArrayList<someObj>();

            // if bla bla
            if (such and such) {
                objList = service.getFromDatabase(someArg);
            } else {
                objList = service.getFromDatabase(anotherarg);
            }

            // Concurrently lock the new cacheList retrieved from the database.
            List<someObj> newValue = Collections.unmodifiableList(objList);

            // Only insert if new value does not exist in cache map
            List<someObj> oldValue = cacheMap.putIfAbsent(orgId, newValue);

            // If old value already exists then we use the old value otherwise we use the new value
            cacheList = ((oldValue != null && !oldValue.isEmpty()) ? oldValue : newValue);
        }
        return cacheList;

    }

РЕДАКТИРОВАТЬ

Я звоню в кеш из контроллера:

public ModelAndView getNotifications(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    User user = getCurrentUser();
    CacheManager cacheManager = new CacheManager();
    List<someObj> objList = new ArrayList<Request>();

    // Get from database
    if (bla bla) {
        objList = getFromDatabase(user);
    }
    // Get from cache
    else {
        Long orgId = user.getUserOrganisation().getId();
        objList = cacheManager.getAllData(orgId, user);      
    }

    return new ModelAndView(SOMEVIEW);
}

который передает полезные данные, которые необходимы методам, которые передают их в метод для вызова базы данных. Тем не менее, я сейчас пытаюсь реорганизовать мой код для использования LoadingCache, но это требует от меня переопределения метода load(), который использует только один параметр, который является ключевым. Мне нужно больше, чем просто ключ, и мне нужно вызвать cacheManager в контроллере, поэтому он вызывает соответствующие методы. Какой метод загрузки? Когда это используется? Когда это называется и как часто? Это лишает законной силы мои другие методы?

1 ответ

Решение

Я считаю, что ваша проблема в том, что вы используете Map вернулся из asMap как твой кеш. asMap задокументировано как Returns a view of the entries stored in this cache as a thread-safe map, Здесь нет ничего, что подсказывало бы, что вы можете использовать Map как твой кеш. Я предлагаю обновить ваш код, чтобы использовать Cache API и вызов put или же get(key, Callable) в кеш напрямую.

Вы можете рассмотреть возможность использования LoadingCache как я обнаружил, что API проще.

РЕДАКТИРОВАТЬ

Итак, во-первых, метод загрузки вызывается только тогда, когда ключ не существует в кэше. Кэш вызывает метод load, чтобы получить значение, которое должно быть возвращено для их ключа, а затем кэширует это значение для использования в следующий раз. Одна из приятных вещей об использовании CacheLoader или Callable заключается в том, что вызов для извлечения данных является потокобезопасным в том смысле, что он вызывается только один раз для каждого ключа, даже если несколько вызовов для одного и того же ключа происходят одновременно.

Если вам нужно передать больше информации, создайте объект-оболочку следующим образом:

 public class MyKey{
       final Long orgId; // true key value
       final User user; // other values needed

       // implement equals and hashCode to ONLY use orgId. This will ensure that
       // the same cached value is returned for all requests with the same
       // orgId which is the ACTUAL key.
  }

Вы также можете сделать то же самое, используя обычный Cache и создать Callable упаковка значений, необходимых.

Я бы предположил, что CacheLoader аннулирует fillCacheIfNecessary, Простой вызов cache.get() внутренне определит, должно ли значение быть восстановлено или уже существует в кэше. Это делает get, check if null, retrieve работать на тебя.

Другие вопросы по тегам