Details
-
Type:
Documentation
-
Status:
Open
-
Priority:
2 Major
-
Resolution: Unresolved
-
Affects Version/s: Site
-
Fix Version/s: None
-
Component/s: Documentation
-
Labels:None
-
Terracotta Target:Unknown
Description
On the page http://www.ehcache.org/documentation/recipes/cachenull the caching of null values is described:
I think there is a problem with the example:
The problem is the use of the EhCacheWrapper because after the call to cache.get(id) you don't know as you get null if the value was null because
1. we put null in the cache
or
2. the element has not been cached before.
Because get is defined in the Wrapper as:
Code:
public V get(final K key) { Element element = getCache().get(key); if (element != null) { return (V) element.getValue(); } return null; }
In either case the element gets fetched from db, but in case 1, since we are caching null values we don't want to fetch the element anymore as we already marked it as being null.
A possible solution, if you want to use a CacheWrapper is do something like in this (similar as EhCache class handles it):
public Value<V> getValueObject(final K key) { Element element = getCache().get(key); return new Value<V>(element); } package ch.ergon.newom.web.service.cache; import net.sf.ehcache.Element; /** * Handles null values correctly. Use this object if you want to know if an * element was retrieved as null from the cache or the value was returned null * because it was not in the cache. * * @param <V> encapsulated value */ public class Value<V> { private final V value; private final boolean inCache; Value(V element) { if (element == null) { inCache = false; } else { inCache = true; } value = element; } Value(Element element) { if (element == null) { value = null; inCache = false; } else { @SuppressWarnings("unchecked") V val = (V) element.getValue(); value = val; inCache = true; } } public V getValue() { return value; } public boolean isInCache() { return inCache; } @Override public String toString() { return "[" + value.toString() + ", " + inCache + "]"; } }
(From http://forums.terracotta.org/forums/posts/list/6096.page)
Activity
| Field | Original Value | New Value |
|---|---|---|
| Status | New [ 10000 ] | Open [ 1 ] |
| Assignee | Issue Review Board [ drb ] | Daniel Zeiter [ scic ] |
| Link | This issue relates to DOC-1018 [ DOC-1018 ] |
| Workflow | Public_workflow_20090225 [ 74092 ] | ExternalProjectWorkflow_201208 [ 87306 ] |
| Workflow | ExternalProjectWorkflow_201208 [ 87306 ] | ExternalProjectWorkflow_201210 [ 96127 ] |
| Workflow | ExternalProjectWorkflow_201210 [ 96127 ] | ExternalProjectWorkflow 201210 [ 99526 ] |
Daniel does this forum post answer your question?
regards
Fiona
From the forums
So this sounds like a discussion of the null object pattern. Specifically, EhCache does support writing nulls for a given key. It's up to your code implementation to recognize the null and not try and do a "put" on a null value if it previously obtained it from the cache. You can do this by using a wrapper like you've done, but a better handler is for the calling method to use the null object pattern, and then not even say call the database or other data store to get the data.
For example in pseudo code:
Get object from Cache
Object is Null, return new instance of object, call setNull(true) on that Object.
Caller gets object, checks "isNull" and if so, returns null. If object is actually null and not a "Null Object instantiation", query the database, store in the cache.
There's a number of patterns for this that work remarkably well. The wrapper you listed above only prevents loading into the cache a null value that was previously put in the cache. Additionally, there might be situations where you'd WANT to do this, such as to update the expiration times or other statistics, etc.