簡體   English   中英

ExpireAfterWrite似乎不起作用

[英]ExpireAfterWrite does not seem to work

我正在嘗試使用Google的Guava緩存,而我只是使用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,因此它會調用適當的方法。 加載方法是什么? 什么時候使用? 什么時候叫,多久叫一次? 它會使我的其他方法無效嗎?

我相信您的問題是您使用從asMap返回的Map作為緩存。 asMap記錄為: Returns a view of the entries stored in this cache as a thread-safe map 這里沒有任何內容建議您可以將Map用作緩存。 我建議更新代碼以使用Cache API並直接在緩存上調用putget(key, Callable)

您可能要考慮使用LoadingCache因為我發現該API更簡單。

編輯

因此,首先,僅當鍵在緩存中不存在時才調用load方法。 緩存調用load方法獲取應為其鍵返回的值,然后緩存該值以供下次使用。 使用CacheLoaderCallable是,檢索數據的調用是線程安全的,因為即使同一關鍵字同時發生多次調用,每個關鍵字僅被調用一次。

如果您需要傳遞更多信息,請創建一個包裝對象,如下所示:

 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為您get, check if null, retrieve工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM