"- One pattern I've seen is where the Cache is accessed by the "client", and if there is a cache miss, the Cache layer accesses the DAO layer and populates the Cache. What do you think about this? Just depends on the application?"
I've implemented a framework this way. I've got something called a CacheManager (which is the brains) which calls a CacheLoader (which accesses the datasource (whatever it is)) when there is a miss to populate the cache.
now this is more of a "client cache" strategy, which not only cuts down on database access, but on the potentially costly communication between the "client" and whatever service you are using, for instance EJB.
Another way could be to cache much closer to the database, or within your DAO layer, Hibernate, for example, can use a cache (EHCache is one choice). I really don't know much about Hibernate, so I can't give you any technical details on this.
oh, and the main entrypoint is a class that represents a proprietary "SystemCache" (not bound to any particular tech). There is basically one method "get(Object key)". This class delegates to the CacheManager, which looks to see if its in the third-party (JCS) cache. If not, it uses the CacheLoader associated with our "SystemCache" object to get it from whatever source.
This is the thing: you write custom CacheLoaders (which is only an interface with one method "loadCacheObject(Object key)) that can get the data whatever way you want. EJB, DAO, text file, http, whatever. the criteria it uses is contained in the key, which can be a String or a non-String class with several fields.
Ok, cool. This is basically the pattern we've started using based on this article. http://www.javaworld.com/javaworld/jw-05-2004/jw-0531-cache.html
So, the client should call the CacheManager, which should call the CacheLoader for that object, which should call the DAO.
If a particular object is not to be cached, it should just call the DAO directly.
yeah, except I've created another "layer" I guess in the "SystemCache" object which owns a reference to the CacheManager and the CacheLoader.
this way your client only needs to call the following:
Object myObj = widgetCache.get("widget1"); (either returns the object, or null if either no object found in data source, or if an exception is thrown, therefore, it looks sort of like a read-only HashMap)
widgetCache was created previously somewhere as:
SystemCache widgetCache = new SystemCache(JCSCacheManager.getInstance(), WidgetCacheLoader.getInstance());
I'm using spring, so we don't create the SystemCache in this manner in our code, but this is the aproximate syntax.