For a simple Post-Tag @ManyToMany scenario like this one @ManyToMany inconsistent data on both side problem
It seems that hibernate's 2nd level cache doesn't know the time to update the aggregation function (ex: count ) like this one :
public int getPostCountByTag(Tag tag)
{
Session session = (Session) em.getDelegate();
Criteria c = session.createCriteria(Post.class);
c.createCriteria("tags")
.add(Restrictions.eq("id", tag.getId()));
c.setProjection(Projections.rowCount());
c.setCacheable(true);
int num = ((Long) c.uniqueResult()).intValue();
return num;
}
And hibernate also doesn't know it's time to update a list like this one :
public List<Post> getPostsByTag(Tag tag, int start, int count)
{
Session session = (Session) em.getDelegate();
Criteria c = session.createCriteria(Post.class);
c.createCriteria("tags")
.add(Restrictions.eq("id", tag.getId()));
c.addOrder(Order.desc("created")); break;
c.setFirstResult(start);
c.setMaxResults(count);
c.setCacheable(true);
return c.list();
}
Each time I add/remove a Tag to/from a Post , these count and list remain unchanged . I know maybe it's because they are cached by c.setCacheable(true) , and I have to manually evict the cache or set the timeout shorter.
But , I wonder if there is any better / smarter way for hibernate to auto detect the cache eviction timing ?
In the example , there are just two methods that are affected by tag's add/remove , but as methods grows , the cache eviction management will become very cumbersome and error-prone . for example :
addTag(Post post , Tag tag)
{
post.addTag(tag);
postDao.update(post);
EntityManagerFactoryUtils.getTransactionalEntityManager(emf).flush();
evict_cache_in_getPostsByTag();
evict_cache_in_getPostCountByTag();
evict_cache_in_getPostsByTagAndBlah();
evict_cache_in_getPostsByTagAndBlahBlah();
evict_cache_in_getPostsByTagAndBlahBlahBlah();
}
removeTag(Post post , Tag tag)
{
post.removeTag(tag);
postDao.update(post);
EntityManagerFactoryUtils.getTransactionalEntityManager(emf).flush();
evict_cache_in_getPostsByTag();
evict_cache_in_getPostCountByTag();
evict_cache_in_getPostsByTagAndBlah();
evict_cache_in_getPostsByTagAndBlahBlah();
evict_cache_in_getPostsByTagAndBlahBlahBlah();
}
This is terrible !!!
I wonder how to solve this n x m problem ? (n is 2 (add/remove) , m is 5 (evicts) , in this sample )
By the way , I found hibernate's cache.evictQueryRegions() seems NOT work at all . I have to manually give each query cache a name (cache region) , and specify which cache region to evict by cache.evictQueryRegion("getTagPostsCount"); , Did I miss anything ? or is it Hibernate's bug ? (updated : after upgrading to Hibernate 3.6.0.Final , the problem is solved , it seems it is 3.5.6's bug)
Hibernate 3.5.6-Final , hibernate-jpa-2.0 , ehcache-1.5.0 , Spring-3.0.4