I am trying to figure out the best way to understand how to cache domain objects
Posted
by
Brett Ryan
on Programmers
See other posts from Programmers
or by Brett Ryan
Published on 2012-11-29T07:44:15Z
Indexed on
2012/11/29
11:20 UTC
Read the original article
Hit count: 268
I've always done this wrong, I'm sure a lot of others have too, hold a reference via a map and write through to DB etc..
I need to do this right, and I just don't know how to go about it. I know how I want my objects to be cached but not sure on how to achieve it. What complicates things is that I need to do this for a legacy system where the DB can change without notice to my application.
So in the context of a web application, let's say I have a WidgetService
which has several methods:
Widget getWidget();
Collection<Widget> getAllWidgets();
Collection<Widget> getWidgetsByCategory(String categoryCode);
Collection<Widget> getWidgetsByContainer(Integer parentContainer);
Collection<Widget> getWidgetsByStatus(String status);
Given this, I could decide to cache by method signature, i.e. getWidgetsByCategory("AA")
would have a single cache entry, or I could cache widgets individually, which would be difficult I believe; OR, a call to any method would then first cache ALL widgets with a call to getAllWidgets()
but getAllWidgets()
would produce caches that match all the keys for the other method invocations. For example, take the following untested theoretical code.
Collection<Widget> getAllWidgets() {
Entity entity = cache.get("ALL_WIDGETS");
Collection<Widget> res;
if (entity == null) {
res = loadCache();
} else {
res = (Collection<Widget>) entity.getValue();
}
return res
}
Collection<Widget> loadCache() {
// Get widgets from underlying DB
Collection<Widget> res = db.getAllWidgets();
cache.put("ALL_WIDGETS", res);
Map<String, List<Widget>> byCat = new HashMap<>();
for (Widget w : res) {
// cache by different types of method calls, i.e. by category
if (!byCat.containsKey(widget.getCategory()) {
byCat.put(widget.getCategory(), new ArrayList<Widget>);
}
byCat.get(widget.getCatgory(), widget);
}
cacheCategories(byCat);
return res;
}
Collection<Widget> getWidgetsByCategory(String categoryCode) {
CategoryCacheKey key = new CategoryCacheKey(categoryCode);
Entity ent = cache.get(key);
if (entity == null) {
loadCache();
}
ent = cache.get(key);
return ent == null ? Collections.emptyList() : (Collection<Widget>)ent.getValue();
}
NOTE: I have not worked with a cache manager, the above code illustrates cache
as some object that may hold caches by key/value pairs, though it's not modelled on any specific implementation.
Using this I have the benefit of being able to cache all objects in the different ways they will be called with only single objects on the heap, whereas if I were to cache the method call invocation via say Spring It would (I believe) cache multiple copies of the objects.
I really wish to try and understand the best ways to cache domain objects before I go down the wrong path and make it harder for myself later. I have read the documentation on the Ehcache website and found various articles of interest, but nothing to give a good solid technique.
Since I'm working with an ERP system, some DB calls are very complicated, not that the DB is slow, but the business representation of the domain objects makes it very clumsy, coupled with the fact that there are actually 11 different DB's where information can be contained that this application is consolidating in a single view, this makes caching quite important.
© Programmers or respective owner