Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid caching when values are null?

Tags:

caching

guava

I am using Guava to cache hot data. When the data does not exist in the cache, I have to get it from database:

public final static LoadingCache<ObjectId, User> UID2UCache = CacheBuilder.newBuilder()         //.maximumSize(2000)         .weakKeys()         .weakValues()         .expireAfterAccess(10, TimeUnit.MINUTES)         .build(         new CacheLoader<ObjectId, User>() {             @Override             public User load(ObjectId k) throws Exception {                 User u = DataLoader.datastore.find(User.class).field("_id").equal(k).get();                 return u;             }         }); 

My problem is when the data does not exists in database, I want it to return null and to not do any caching. But Guava saves null with the key in the cache and throws an exception when I get it:

com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader returned null for key shisoft.

How do we avoid caching null values?

like image 261
Shisoft Avatar asked Nov 14 '12 12:11

Shisoft


People also ask

What is null cache?

That means you could reuse it anywhere in your application. If your generic cache is designed to take null as not cached. Then it's not worthy to change the behavior if only one or two of your caches are taking null as cached values.

Does caffeine cache null values?

The cache does not allow storing null values. If you perform a computation and return null then this indicates the data doesn't exist and the caller receives null.

What is spring cache?

Spring Cache uses the parameters of the method as key and the return value as a value in the cache. When the method is called the first time, Spring will check if the value with the given key is in the cache. It will not be the case, and the method itself will be executed.


1 Answers

Just throw some Exception if user is not found and catch it in client code while using get(key) method.

new CacheLoader<ObjectId, User>() {     @Override     public User load(ObjectId k) throws Exception {         User u = DataLoader.datastore.find(User.class).field("_id").equal(k).get();         if (u != null) {              return u;         } else {              throw new UserNotFoundException();         }     } } 

From CacheLoader.load(K) Javadoc:

Returns:     the value associated with key; must not be null   Throws:     Exception - if unable to load the result 

Answering your doubts about caching null values:

Returns the value associated with key in this cache, first loading that value if necessary. No observable state associated with this cache is modified until loading completes.

(from LoadingCache.get(K) Javadoc)

If you throw an exception, load is not considered as complete, so no new value is cached.

EDIT:

Note that in Caffeine, which is sort of Guava cache 2.0 and "provides an in-memory cache using a Google Guava inspired API" you can return null from load method:

 Returns:    the value associated with key or null if not found 

If you may consider migrating, your data loader could freely return when user is not found.

like image 164
Xaerxess Avatar answered Sep 21 '22 19:09

Xaerxess