I’m using Hibernate 4.3.11.Final with Spring 3.2.11.RELEASE. I’m confused as to why my cache eviction isn’t working. I have this set up in my DAO …
@Override
@Caching(evict = { @CacheEvict("main") })
public Organization save(Organization organization)
{
    return (Organization) super.save(organization);
}
@Override
@Cacheable(value = "main")
public Organization findById(String id)
{
    return super.find(id);
}
and here’s my Spring config …
<cache:annotation-driven key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="org.mainco.subco.myproject.util.CacheKeyGenerator" />
<bean id="cacheManager"
    class="org.springframework.cache.ehcache.EhCacheCacheManager"
    p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
    p:configLocation="classpath:ehcache.xml"
    p:shared="true" />
<util:map id="jpaPropertyMap">
    <entry key="hibernate.show_sql" value="true" />
    <entry key="hibernate.dialect" value="org.mainco.subco.myproject.jpa.subcoMysql5Dialect" />
    <entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
    <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
    <entry key="hibernate.cache.use_second_level_cache" value="true" />
    <entry key="hibernate.cache.use_query_cache" value="false" />
    <entry key="hibernate.generate_statistics" value="true" />
    <entry key="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE" />
</util:map>
<bean id="sharedEntityManager"
    class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Yet in the below test, my entity is not getting evicted from the cache, which I know because the line with “hit count #3:” prints out “3” whereas the line with "hit count #2:” prints out “2”.
private net.sf.ehcache.Cache m_cache
@Autowired 
private net.sf.ehcache.CacheManager ehCacheManager;
@Before
public void setup()
{
    m_cache = ehCacheManager.getCache("main");
    m_transactionTemplate = new TransactionTemplate(m_transactionManager);
}   // setup
...
@Test
public void testCacheEviction()
{
    final String orgId = m_testProps.getProperty("test.org.id");
    // Load the entity into the second-level cache
    m_transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {            
        m_orgSvc.findById(orgId);
        return null;
    });
    final long hitCount = m_cache.getStatistics().getCacheHits();
    System.out.println("hit count #1:" + hitCount);
    m_transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {            
        final Organization org = m_orgSvc.findById(orgId);
        System.out.println("hit count:" + m_cache.getStatistics().getCacheHits());
        org.setName("newName");
        m_orgSvc.save(org);
        return null;
    });
    // Reload the entity.  This should not incur a hit on the cache.
    m_transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {
        System.out.println("hit count #2:" + m_cache.getStatistics().getCacheHits());
        final Organization newOrg = m_orgSvc.findById(orgId);
        System.out.println("hit count #3:" + m_cache.getStatistics().getCacheHits());
        return null;
    });
What is the right configuration to allow me to evict an entity from my second-level cache?
Edit: The CacheKeyGenerator class I referenced in my application context is defined below
public class CacheKeyGenerator implements KeyGenerator 
{
    @Override
    public Object generate(final Object target, final Method method, 
      final Object... params) {
        final List<Object> key = new ArrayList<Object>();
        key.add(method.getDeclaringClass().getName());
        key.add(method.getName());
        for (final Object o : params) {
            key.add(o);
        }
        return key;
    }  
}
As such I don’t have to define a “key” for each @Cacheable annotation which I prefer (less code). However, I don’t know how this applies to CacheEviction. I thought the @CacheEvict annotation would use the same key-generation scheme.
 
                        
You are missing the cache keys for both
@Cacheableand@CacheEvict. Because of that, the two operations are using different cache keys and hence the entity is not evicted.From the JavaDocs for
@Cacheable.key:So,
@Cacheable(value = "main") public Organization findById(String id)means that the returned object (of typeOrganization) will be cached with the keyid.Similarly,
@Caching(evict = { @CacheEvict("main") }) public Organization save(Organization organization)means that the string representation oforganizationwill be considered as the cache key.The solution is to make the following changes:
This will force the two cache operations to use the same key.