Hi robcos,
Here is the original class with an updated disableSecondLevelCache() method so that it clears the cache rather than disabling the Session's use of the cache; it relies on casting the SessionFactory to SessionFactoryImpl:
Code:
package org.spring.forum;
import java.util.Collection;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cache.Cache;
import org.hibernate.impl.SessionFactoryImpl;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.test.AbstractTransactionalSpringContextTests;
public abstract class AbstractHibernateCacheClearableTest extends AbstractTransactionalSpringContextTests {
/** Hibernate template to use for disabling second level cache. */
private HibernateTemplate hibernateTemplate;
/** Whether to disable second level cache; defaults to true. */
private boolean disableSecondLevelCache = true;
@Override
protected void onSetUpInTransaction() throws Exception {
if (this.disableSecondLevelCache) {
disableSecondLevelCache();
}
}
/**
* Performs the actual disabling of the Hibernate second-level cache.
*/
protected void disableSecondLevelCache() {
this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl)session.getSessionFactory();
Map cacheRegionsMap = sessionFactoryImpl.getAllSecondLevelCacheRegions();
Collection<Cache> cacheRegions = cacheRegionsMap.values();
for (Cache cache : cacheRegions) {
cache.clear();
}
return null;
}
});
}
/**
* Sets the HibernateTemplate for disabling the Hibernate second-level
* cache.
*
* @param hibernateTemplate the HibernateTemplate for disabling the
* Hibernate second-level cache.
*/
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
/**
* Sets whether to disable the Hibernate second-level cache. Defaults to
* true.
*
* @param disableSecondLevelCache whether to disable the Hibernate
* second-level cache.
*/
public void setDisableSecondLevelCache(boolean disableSecondLevelCache) {
this.disableSecondLevelCache = disableSecondLevelCache;
}
/**
* Checks whether disabling of Hibernate second-level cache should occur.
* Can be overridden by subclasses to return false to allow second-level
* cache usage (or the disableSecondLevelCache can be set to false, either
* programmatically or through injection).
*
* @return whether disabling of Hibernate second-level cache should occur.
*/
public boolean isDisableSecondLevelCache() {
return this.disableSecondLevelCache;
}
}
The above code calls Cache.clear for every cache region. An alternative method implementation that might work is defined below, which retrieves all mapped classes and calls Session.evictEntity for each:
Code:
protected void disableSecondLevelCache() {
this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl)session.getSessionFactory();
// Every persistent class extends java.lang.Object, so the following call will return all persistent classes
String[] persistentClasses = sessionFactoryImpl.getImplementors("java.lang.Object");
for (String persistentClass : persistentClasses) {
sessionFactoryImpl.evictEntity(persistentClass);
}
return null;
}
});
}
The relevant APIs are SessionFactoryImpl.getAllSecondLevelCacheRegions and SessionFactoryImpl.getImplementors.
I hope one of those implementations actually works!
-Arthur Loder