I am using the EhCache's decorator SelfPopulatingCache
and have an issue when the cache tries to load a new entry, but it's non-existent (i.e. it doesn't exist in the database). So the cache will put a null
value into the cache, to unblock any other gets on the key, but then the next thread will do the same database call because it received 'null' from the cache. which means it thinks the entry needs to be loaded - even though in reality it's null because the data doesn't exists anywhere. I feel like I'm doing something wrong.
(pseudo code)
Value v = cache.get(key); // multiple threads will block here
if (v == null)
cache.put(key, getValueFromDB()); // this might put a null value
My current solution is to not put null, but to put a placeholder Object
and check for it.
Value v = cache.get(key);
if (v == null)
cache.put(key, getValueFromDB());
else if (v == NOENTRYOBJECT)
return null;
else
return v;
Thoughts?
sf. ehcache. disabled=true in the Java command line) disables caching in ehcache. If disabled, no elements can be added to a cache (puts are silently discarded).
1. Overview. In this article, we will introduce Ehcache, a widely used, open-source Java-based cache. It features memory and disk stores, listeners, cache loaders, RESTful and SOAP APIs and other very useful features.
Data stores supported by Ehcache include: On-Heap Store - Utilizes Java's on-heap RAM memory to store cache entries. This tier utilizes the same heap memory as your Java application, all of which must be scanned by the JVM garbage collector.
Ehcache as a plug-in second-level cache for Hibernate – Automatically cache common queries in memory to substantially lower latency. BigMemory for an in-memory store – Leverage off-heap physical memory to keep more of the data set close to your application and out of reach of Java garbage collection.
We do something similar. In our case, we enter Boolean.FALSE
into the cache if the requested key doesn't correspond to a valid item. It basically tells the calling code that the key that it asked for doesn't match any data. You need to make one call to the db on the first request for that key to discover that it doesn't correspond to valid data, but subsequent calls are spared the db lookup. Of course, if data is ever entered into the db for that key, you need to be sure to invalidate that cache entry (otherwise you'll be returning Boolean.FALSE even though there is actual data available).
Not sure if my response helps that much (it's not an alternative approach), but it at least validates that you're not alone in your approach.
BTW, I don't think this is unique to EHCache's SelfPopulatingCache.
The typical pattern is not to recheck the database if the item's KEY exists in the cache at all, rather than the VALUE.
The pattern is described in the ehcache docs here: Caching Empty Values.
Typically, but not always, get
returns an Element
, so get(id)
won't be null if put(id, value)
was ever previously called, even if value is null.
Note that this depends on the cache implementation. The ehcache documentation seems to suggest that it should always work, but BlockingCache
(and its descendants) does NOT allow putting null values into the cache. The base ehcache Cache
object does allow null values to be stored in the cache (as do many examples and custom implementations).
In all I think the solution you already have (placeholder value object), also works and should achieve the same result as the ehcache base Cache
class and documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With