Caching is an essential mechanism in providing efficient usage of resources in many systems. Caching allows objects to be retained and returned rapidly without having to make an extra call to the datastore. JPA1 defines very little about caching, but the JPA2 specification improves on this. DataNucleus provides a definition of caching at 2 levels. The 2 levels of caching available are
You can think of a cache as a Map, with values referred to by keys. In the case of JPA, the key is the object identity (identity is unique in JPA).
The Level 1 Cache is always enabled. There are inbuilt types for the Level 1 Cache available for selection. DataNucleus supports the following types of Level 1 Cache.
You can specify the type of Level 1 Cache by providing the persistence property datanucleus.cache.level1.type . You set this to the value of the type required. If you want to remove all objects from the L1 cache programmatically you should use em.clear() but bear in mind the other things that this does. Objects are placed in the L1 cache (and updated there) during the course of the transaction. This provides rapid access to the objects in use in the users application and is used to guarantee that there is only one object with a particular identity at any one time for that EntityManager. When the EM is closed the cache is cleared.
By default the Level 2 Cache is enabled. The user can configure the Level 2 Cache if they so wish; by use of the persistence property datanucleus.cache.level2.type . You set this to "type" of cache required. With the Level 2 Cache you currently have the following options. With the Level 2 Cache you currently have the following options.
The EHCache, OSCache, SwarmCache, Coherence, javax.cache, Cacheonix, and Memcache caches are available in the datanucleus-cache plugin. In addition you can control the mode of operation of the L2 cache. You do this using the persistence property datanucleus.cache.level2.mode (or javax.persistence.sharedCache.mode . The default is UNSPECIFIED which means that DataNucleus will cache all objects of entities unless the entity is explicitly marked as not cacheable. The other options are NONE (don't cache ever), ALL (cache all entities regardless of annotations), ENABLE_SELECTIVE (cache entities explicitly marked as cacheable), or DISABLE_SELECTIVE (cache entities unless explicitly marked as not cacheable - i.e same as our default). Objects are placed in the L2 cache when you commit() the transaction of a EntityManager. This means that you only have datastore-persisted objects in that cache. Also, if an object is deleted during a transaction then at commit it will be removed from the L2 cache if it is present.
The majority of times when using a JPA-enabled system you will not have to take control over any aspect of the caching other than specification of whether to use a Level 2 Cache or not. With JPA2 and DataNucleus you have the ability to control which objects remain in the cache. This is available via a method on the EntityManagerFactory . EntityManagerFactory emf = Persistence.createEntityManagerFactory(persUnitName, props); Cache cache = emf.getCache(); The Cache interface provides methods to control the retention of objects in the cache. You have 2 types of methods
You can also control which classes are put into a Level 2 cache. So with the following JPA2 annotation @Cacheable, no objects of type MyClass will be put in the L2 cache.
@Cacheable(false)
@Entity
public class MyClass
{
...
}If you want to control which fields of an object are put in the Level 2 cache you can do this using an extension annotation on the field. This setting is only required for fields that are relationships to other persistable objects. Like this
public class MyClass
{
...
Collection values;
@Extension(vendorName="datanucleus", key="cacheable", value="false")
Collection elements;
}So in this example we will cache "values" but not "elements". If a field is cacheable then
DataNucleus provides a simple wrapper to javax.cache's caches. To enable this you should set the persistence properties
datanucleus.cache.level2.type=javax.cache
datanucleus.cache.level2.cacheName={cache name}
datanucleus.cache.level2.timeout={expiration time in millis - optional}Use version 3.0 of datanucleus-cache if you want the early access release API of javax.cache (pre-2010). Use version 3.1 of datanucleus-cache if you want the later API post-2010.
DataNucleus provides a simple wrapper to Oracle's Coherence caches. This currently takes the NamedCache interface in Coherence and instantiates a cache of a user provided name. To enabled this you should set the following persistence properties
datanucleus.cache.level2.type=coherence
datanucleus.cache.level2.cacheName={coherence cache name}The Coherence cache name is the name that you would normally put into a call to CacheFactory.getCache(name). You have the benefits of Coherence's distributed/serialized caching. If you require more control over the Coherence cache whilst using it with DataNucleus, you can just access the cache directly via DataStoreCache cache = pmf.getDataStoreCache(); NamedCache tangosolCache = ((TangosolLevel2Cache)cache).getTangosolCache();
DataNucleus provides a simple wrapper to EHCache's caches. To enable this you should set the persistence properties
datanucleus.cache.level2.type=ehcache
datanucleus.cache.level2.cacheName={cache name}
datanucleus.cache.level2.configurationFile={EHCache configuration file (in classpath)}The EHCache plugin also provides an alternative L2 Cache that is class-based. To use this you would need to replace "ehcache" above with "ehcacheclassbased".
DataNucleus provides a simple wrapper to OSCache's caches. To enable this you should set the persistence properties
datanucleus.cache.level2.type=oscache
datanucleus.cache.level2.cacheName={cache name}
DataNucleus provides a simple wrapper to SwarmCache's caches. To enable this you should set the persistence properties
datanucleus.cache.level2.type=swarmcache
datanucleus.cache.level2.cacheName={cache name}
DataNucleus provides a simple wrapper to Spymemcached caches and Xmemcached caches. . To enable this you should set the persistence properties
datanucleus.cache.level2.type=spymemcached [or "xmemcached"]
datanucleus.cache.level2.cacheName={prefix for keys, to avoid clashes with other memcached objects}
datanucleus.cache.level2.memcached.servers=...
datanucleus.cache.level2.memcached.expireSeconds=...datanucleus.cache.level2.memcached.servers is a space separated list of memcached hosts/ports, e.g. host:port host2:port. datanucleus.cache.level2.memcached.expireSeconds if not set or set to 0 then no expire
DataNucleus provides a simple wrapper to Cacheonix. To enable this you should set the persistence properties
datanucleus.cache.level2.type=cacheonix
datanucleus.cache.level2.cacheName={cache name}Note that you can optionally also specify
datanucleus.cache.level2.timeout={timeout-in-millis (default=60)}
datanucleus.cache.level2.configurationFile={Cacheonix configuration file (in classpath)}and define a cacheonix-config.xml like
<?xml version="1.0"?>
<cacheonix>
<local>
<!-- One cache per class being stored. -->
<localCache name="mydomain.MyClass">
<store>
<lru maxElements="1000" maxBytes="1mb"/>
<expiration timeToLive="60s"/>
</store>
</localCache>
<!-- Fallback cache for classes indeterminable from their id. -->
<localCache name="datanucleus">
<store>
<lru maxElements="1000" maxBytes="10mb"/>
<expiration timeToLive="60s"/>
</store>
</localCache>
<localCache name="default" template="true">
<store>
<lru maxElements="10" maxBytes="10mb"/>
<overflowToDisk maxOverflowBytes="1mb"/>
<expiration timeToLive="1s"/>
</store>
</localCache>
</local>
</cacheonix> |