|
JCS Usage in HibernateOverviewNote: JCS is not directly supported by Hibernate, but can be used through the cache provider plugin system. This page is likely very old. Hibernate comes bundled with cache providers for four open source caching systems, EHCAche, SwarmCache, OSCache, and JBoss Cache./ The JCS project site can be found at http://jakarta.apache.org/turbine/jcs/ . JCS can be used to store commonly accessed domain objects, avoiding expensive database access. This document is a supplement to the existing Hibernate documentation, looking at loading strategies and their impact on cacheing. ExamplesExamples given in this document refer to a Country domain object. Country has a many-to-one association with Region and a many-to-many association with CreditCard. Region has a many-to-one association with itself, representing a parent region. Test data used:
Retrieving the Country object Australia will create:
Cached objects may be read-write or read-only. All examples use the read-only syntax. Performance TimingsPerformance timings were produced in the following environment: Application Server
Database Server
The first time a cacheable query is done, the cache has no effect on speed. On the second and successive queries, the cache will be populated and available to be hit. Timings are given for the LRU memory cache with no timeout. <hibernatedoclet ... />hibernatedoclet, a module of the xdoclet project (see http://xdoclet.sourceforge.net) can be used to automate the production of Hibernate mapping files. In hibernatedoclet, jcs cache tags can be inserted at the class level, in which case the object is cacheable, or at the method level for the following Hibernate types: set, list, map, bag, array and primitive-array. See http://hibernate.sourceforge.net/hibernate-mapping.dtd for more information. class level
/*
* @hibernate.class table="COUNTRY"
* @hibernate.jcs-cache usage="read-only"
*/
public class Country { ...
The class level tag will make the object cacheable, but not collections representing many to many relationships. method level
/**
* @hibernate.set role="creditCards" table="COUNTRY_CREDIT_CARD"
* @hibernate.jcs-cache usage="read-only"
* @hibernate.collection-key column="FK_COUNTRY"
* @hibernate.collection-many-to-many class="com.gregluck.domain.CreditCard" column="FK_CREDIT_CARD"
*/
public Set getCreditCards() {
return creditCards;
}
The method level tag applied to a set, list, map, bag, array or primitive-array will make the collection cacheable. If the jcs-cache tag is added to all collection types in an object, then the entire object is cacheable. (As of xdoclet 1.2 beta2, the method level jcs-cache tag is not implemented. You should work from XDoclet CVS for now. The patch should make it into xdoclet 1.2 beta 3.) Object Loading MethodsThe following discussion assumes that <jcs-cache usage="read-only" /> tags are set at the class and method level in the Hibernate mapping files for all classes. In our example this is Country, Region and CreditCard. If Region does not have jcs-cache set, its Region member variable will never be cached. Session.load()Session.load(...) will attempt to load the object and any member variables from cache. In our Country example, the object graph is 100% cached. Example country = (Country) session.load(Country.class, id); Performance
Strategies for Use Session.load is the fastest way of loading an object where the id is known. Session.find()Session.find(...) uses Hibernate HQL to execute a query. It is translated into SQL and executed against the database. The cache is never utilised by find(), until Hibernate tries to resolve associations after the initial query. (Of course, find() does add objects to the cache.) Example
Long id = new Long(5);
List countries = session.find(
"from country in class com.gregluck.domain.Country where country.id > ? ",
id,
Hibernate.LONG);
This example will load all countries with an id greater than 5. Performance
Strategies for Use Session.find() cannot efficiently take advantage of the cache. However, it can be used to efficiently load objects into the cache. Session.iterate()Session.iterate(...) uses Hibernate HQL to execute a query which returns object ids only. As objects are iterated over they are loaded using load() transparently. The result of the first query (which returns ids) is never cached. The iteration is cached. Example
Collection countries = new ArrayList();
session = sessionFactory.openSession();
Iterator i = session.iterate(
"from country in class com.gregluck.domain.Country");
while (i.hasNext()) {
countries.add(i.next());
}
This example will load all countries. Performance
Strategies for Use Session.iterate() should be used in preference to Session.find() to utilise the cache. Additional performance can be achieved by making association collections such as Set load lazily. Enable lazy loading using lazy="true" . An example using hibernate doclet is: * @hibernate.set role="creditCards" table="COUNTRY_CREDIT_CARD" lazy="true" Cache Configuration Using cache.ccfJCS is configured in the file cache.ccf. This file must be in the classpath and loadable by this.getClass().getResourceAsStream() by Hibernate. Unfortunately this seems to be problematic for some application servers. In Orion the only thing which seems to work is adding cache.ccf to the jcs.jar and placing jcs.jar in Orion's lib directory. Another Option in Orion is to put the cache.ccf file in =ejb-ap=p directory. A cache.ccf file which works with the above examples is: # DEFAULT CACHE REGION (memory cache) jcs.default=DC jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.default.cacheattributes.MaxObjects=2000 jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.default.elementattributes=org.apache.jcs.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLifeSeconds=24000 jcs.default.elementattributes.IdleTime=180000 jcs.default.elementattributes.IsSpool=false jcs.default.elementattributes.IsRemote=false jcs.default.elementattributes.IsLateral=false #Country Cache jcs.region.com.gregluck.domain.Country=DC jcs.region.com.gregluck.domain.Country.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.region.com.gregluck.domain.Country.cacheattributes.MaxObjects=1000 jcs.region.com.gregluck.domain.Country.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.region.com.gregluck.domain.Country.cacheattributes.UseMemoryShrinker=true jcs.region.com.gregluck.domain.Country.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.region.com.gregluck.domain.Country.cacheattributes.ShrinkerIntervalSeconds=60 jcs.region.com.gregluck.domain.Country.elementattributes=org.apache.jcs.engine.ElementAttributes jcs.region.com.gregluck.domain.Country.elementattributes.IsEternal=false jcs.region.com.gregluck.domain.Country.elementattributes.MaxLifeSeconds=240 jcs.region.com.gregluck.domain.Country.elementattributes.IdleTime=180 jcs.region.com.gregluck.domain.Country.elementattributes.IsSpool=false jcs.region.com.gregluck.domain.Country.elementattributes.IsRemote=false jcs.region.com.gregluck.domain.Country.elementattributes.IsLateral=false #Region Cache jcs.region.com.gregluck.domain.Region=DC jcs.region.com.gregluck.domain.Region.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.region.com.gregluck.domain.Region.cacheattributes.MaxObjects=1000 jcs.region.com.gregluck.domain.Region.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.region.com.gregluck.domain.Region.cacheattributes.UseMemoryShrinker=true jcs.region.com.gregluck.domain.Region.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.region.com.gregluck.domain.Region.cacheattributes.ShrinkerIntervalSeconds=60 jcs.region.com.gregluck.domain.Region.elementattributes=org.apache.jcs.engine.ElementAttributes jcs.region.com.gregluck.domain.Region.elementattributes.IsEternal=false jcs.region.com.gregluck.domain.Region.elementattributes.MaxLifeSeconds=240 jcs.region.com.gregluck.domain.Region.elementattributes.IdleTime=180 jcs.region.com.gregluck.domain.Region.elementattributes.IsSpool=false jcs.region.com.gregluck.domain.Region.elementattributes.IsRemote=false jcs.region.com.gregluck.domain.Region.elementattributes.IsLateral=false #CreditCard Cache jcs.region.com.gregluck.domain.CreditCard=DC jcs.region.com.gregluck.domain.CreditCard.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.region.com.gregluck.domain.CreditCard.cacheattributes.MaxObjects=1000 jcs.region.com.gregluck.domain.CreditCard.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.region.com.gregluck.domain.CreditCard.cacheattributes.UseMemoryShrinker=true jcs.region.com.gregluck.domain.CreditCard.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.region.com.gregluck.domain.CreditCard.cacheattributes.ShrinkerIntervalSeconds=60 jcs.region.com.gregluck.domain.CreditCard.elementattributes=org.apache.jcs.engine.ElementAttributes jcs.region.com.gregluck.domain.CreditCard.elementattributes.IsEternal=false jcs.region.com.gregluck.domain.CreditCard.elementattributes.MaxLifeSeconds=240 jcs.region.com.gregluck.domain.CreditCard.elementattributes.IdleTime=180 jcs.region.com.gregluck.domain.CreditCard.elementattributes.IsSpool=false jcs.region.com.gregluck.domain.CreditCard.elementattributes.IsRemote=false jcs.region.com.gregluck.domain.CreditCard.elementattributes.IsLateral=false # System CACHE REGION (unused) #jcs.system.groupIdCache=DC #jcs.system.groupIdCache.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes #jcs.system.groupIdCache.cacheattributes.MaxObjects=10000 #jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache #Auxiliary CACHE (disk cache) (unused) #jcs.auxiliary.DC=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory #jcs.auxiliary.DC.attributes=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes #jcs.auxiliary.DC.attributes.DiskPath=cache #Lateral TCP Cache (unused) #jcs.auxiliary.LTCP=org.apache.jcs.auxiliary.lateral.LateralCacheFactory #jcs.auxiliary.LTCP.attributes=org.apache.jcs.auxiliary.lateral.LateralCacheAttributes #jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP #jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1111 #jcs.auxiliary.LTCP.attributes.TcpListenerPort=1110 #jcs.auxiliary.LTCP.attributes.PutOnlyMode=false In this file separate regions are set up for Country, Region and CreditCard so that different timeouts can be set. Though not shown, regions can also be set up for collections which are member variables e.g. Country/CreditCard. A warning on IndexedDiskCacheThe default disk cache, invoked with the following line suffers from deadlocks. jcs.auxiliary.DC=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory See http://forum.hibernate.org/viewtopic.php?t=924937 for more information. Manual Manipulation of JCSThe Hibernate API is just enough for Hibernate to plug JCS into its existing Cache framework. For programmatic manipulation of caches beyond this, you can use the JCS API. See http://jakarta.apache.org/turbine/jcs/apidocs/index.html . With the API you can obtain a CacheManager, then Caches and manipulate those caches. Obtaining the CompositeCacheManager instanceThe examples shown use the CompositeCacheManager. It is a singleton within a JVM and can be readily obtained from a static getInstance() method. CompositeCacheManager cacheManager = CompositeCacheManager.getInstance(); Obtaining a CacheYou can list caches with
String[] names = cacheManager.getCacheNames();
for (int i = 0; i < names.length; i++) {
LOG.debug("Cache: " + names[i]);
}
and obtain a cache using:
CompositeCache cache = cacheManager.getCache("com.gregluck.domain.Country");
Emptying a CacheTo empty all objects in a cache you can use: cache.removeAll(); Warning: This method is known to cause a memory leak. See http://forum.hibernate.org/viewtopic.php?p=2175231#2175231 for more information. Comments: This is an excellent introduction to the uses of JCS in Hibernate. Thank you! -Kevin http://www.kevinelliott.net |
||||||||