Call us: +1-415-738-4000
Ehcache can easily be combined with your existing JDBC code. Whether you access JDBC directly, or have a DAO/DAL layer, Ehcache can be combined with your existing data access pattern to speed up frequently accessed data to reduce page load times, improve performance, and reduce load from your database.
This page discusses how to add caching to a JDBC application using the commonly used DAO/DAL layer patterns.
If your application already has a DAO/DAL layer, this is a natural place to add caching. To add caching, follow these steps:
Normally, you will want to cache the following kinds of method calls:
Example methods that are commonly cacheable:
public V getById(final K id); public CollectionfindXXX(...);
Your DAO is probably already being managed by Spring or Guice, so simply
add a setter method to your DAO layer such as setCache(Cache cache).
Configure the cache as a bean in your Spring or Guice config, and then
use the the frameworks injection methodology to inject an instance of
the cache.
If you are not using a DI framework such as Spring or Guice, then you will need to instantiate the cache during the bootstrap of your application. As your DAO layer is being instantiated, pass the cache instance to it.
Now that your DAO layer has a cache reference, you can start to use it. You will want to consider using the cache using one of two standard cache access patterns:
You can read more about these in the Concepts cache-as-sor and Concepts cache-aside sections.
Here is some example code that demonstrates a DAO based cache using a cache aside methodology wiring it together with Spring.
This code implements a PetDao modeled after the Spring Framework PetClinic sample application.
It implements a standard pattern of creating an abstract GenericDao implementation which all Dao implementations will extend.
It also uses Spring's SimpleJdbcTemplate to make the job of accessing the database easier.
Finally, to make Ehcache easier to work with in Spring, it implements a wrapper that holds the cache name.
The following are relevant snippets from the example files. A full project will be available shortly.
Simple get/put wrapper interface.
public interface CacheWrapper<K, V>
{
void put(K key, V value);
V get(K key);
}
The wrapper implementation. Holds the name so caches can be named.
public class EhCacheWrapper<K, V> implements CacheWrapper<K, V>
{
private final String cacheName;
private final CacheManager cacheManager;
public EhCacheWrapper(final String cacheName, final CacheManager cacheManager)
{
this.cacheName = cacheName;
this.cacheManager = cacheManager;
}
public void put(final K key, final V value)
{
getCache().put(new Element(key, value));
}
public V get(final K key, CacheEntryAdapter<V> adapter)
{
Element element = getCache().get(key);
if (element != null) {
return (V) element.getValue();
}
return null;
}
public Ehcache getCache()
{
return cacheManager.getEhcache(cacheName);
}
}
The Generic Dao. It implements most of the work.
public abstract class GenericDao<K, V extends BaseEntity> implements Dao<K, V>
{
protected DataSource datasource;
protected SimpleJdbcTemplate jdbcTemplate;
/* Here is the cache reference */
protected CacheWrapper<K, V> cache;
public void setJdbcTemplate(final SimpleJdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void setDatasource(final DataSource datasource) {
this.datasource = datasource;
}
public void setCache(final CacheWrapper<K, V> cache) {
this.cache = cache;
}
/* the cacheable method */
public V getById(final K id) {
V value;
if ((value = cache.get(id)) == null) {
value = this.jdbcTemplate.queryForObject(findById, mapper, id);
if (value != null) {
cache.put(id, value);
}
}
return value;
}
/** rest of GenericDao implementation here **/
/** ... **/
/** ... **/
/** ... **/
}
The Pet Dao implementation, really it doesn't need to do anything unless specific methods not available via GenericDao are cacheable.
public class PetDaoImpl extends GenericDao<Integer, Pet> implements PetDao
{
/** ... **/
}
We need to configure the JdbcTemplate, Datasource, CacheManager, PetDao, and the Pet cache using the spring configuration file.
The Spring configuration file.
<!-- datasource and friends -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.FasterLazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="dataSourceTarget"/>
</bean>
<bean id="dataSourceTarget" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="initialPoolSize" value="50"/>
<property name="maxPoolSize" value="300"/>
<property name="minPoolSize" value="30"/>
<property name="acquireIncrement" value="2"/>
<property name="acquireRetryAttempts" value="0"/>
</bean>
<!-- jdbctemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<!-- the cache manager -->
<bean id="cacheManager" class="EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:${ehcache.config}"/>
</bean>
<!-- the pet cache to be injected into the pet dao -->
<bean name="petCache" class="EhCacheWrapper">
<constructor-arg value="pets"/>
<constructor-arg ref="cacheManager"/>
</bean>
<!-- the pet dao -->
<bean id="petDao" class="PetDaoImpl">
<property name="cache" ref="petCache"/>
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="datasource" ref="dataSource"/>
</bean>
