Ну, во-первых, ваш доступ не синхронизирован, так что это большой источник проблем. Чтение из HttpRuntime Cache гарантированно является потокобезопасным, поэтому вам действительно следует попробовать прочитать свой элемент в качестве первого шага в каждой операции кэша.
Между проверкой, если Exists
и фактическим извлечением предмета, может произойти много вещей (например, вашего предмета там больше нет). Вы должны получить дескриптор элемента, который вы ищете, и, если его там нет, предоставьте поточно-ориентированную вставку, извлекая его из постоянного хранилища данных.
Таким образом, ваша логика Add
попадет внутрь вашего Get
ЕСЛИ данных там нет. Нет ничего принципиально неправильного в предоставлении отдельной логики Add
, и вы должны измерить стоимость многократного попадания в базу данных по сравнению с блокировкой дальнейших запросов для этого конкретного фрагмента данных.
T GetT(string key)
{
T item = (cache.Get(key) as T);
if (item == null)
{
lock (yourSyncRoot)
{
// double check it here
item = (cache.Get(key) as T);
if (item != null)
return item;
item = GetMyItemFromMyPersistentStore(key); // db?
if (item == null)
return null;
string[] dependencyKeys = {your, dependency, keys};
cache.Insert(key, item, new CacheDependency(null, dependencyKeys),
absoluteExpiration, slidingExpiration, priority, null);
}
}
return item;
}
В зависимости от вашей политики истечения срока действия вы получите свои данные в памяти и обеспечите быстрый и синхронизированный доступ к ним, но, как я уже сказал, измерьте их и настройте в соответствии с вашими потребностями. В вашей бизнес-логике после обновления вашего предмета и правильного сохранения его в постоянном хранилище, просто удалите его из кэша, и следующий вызов вашего Get
получит его снова.