Caching layer (hibernate 2nd level)

433 views
Skip to first unread message

Sport11can

unread,
Dec 4, 2009, 5:06:58 PM12/4/09
to play-framework
I have been playing with caching with hibernate within the Play!
framework. There are 2 levels that what to talk about:

1. Hibernate cache plugin:

For now I have been using http://code.google.com/p/hibernate-memcached/
just including it in the app/lib folder and adding the following to
the application.conf file:


hibernate.cache.provider_class=com.googlecode.hibernate.memcached.MemcachedCacheProvider
hibernate.cache.use_query_cache=true
hibernate.memcached.servers=127.0.0.1:11211
hibernate.memcached.cacheTimeSeconds=300

I want to create a new hibernate cache provider that will utilize the
play.cache.Cache interface.
Obviously my current implementation is not ideal as the memcache
configuration (servers etc) are duplicated (once for play, once for
hibernate-memcached).

How do you think this would be best implemented? module?
seperately? in the play.cache / play.db / play.data package?


2. Hibernate 2nd level cache for models and Query Cache

I have general model and relationship (OneToMany etc) caching
accomplished via hibernate annotations
@org.hibernate.annotations.Cache(usage =
CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)

Kinda sucks, as I don't think the JPA has any support for caching so
we wouldn't have to be tied to the hibernate implementation being
used. Any thoughts here?

Query Cache

So then I started wanting to use the hibernate query cache. I know
you could implement this functionality yourself { Check Cache, return,
Else Get / Save, return } but the complications come into play knowing
when to refresh the cached query if something was to be updated.

return User.find("order by _updated desc").setCacheable(true).fetch
();

Example. Say we wanted to get a list of the current users ordered by
name. We would currently do something like this.

public static List<User> findAllOrderByName()
{
return User.find("order by name").fetch();
}

Then we could add the calls to implement caching. As mentioned you
don't know that the cache should be refreshed when any other User is
saved. You could hook into the save() function (or postCommit) and
just clear the cache for this entry (and any others you have), but it
would be nice to just let hibernate take care of it.

So my current brute force implementation is (I saw how the underlying
hibernate session was obtained in the JpaSupport class):

public static List<User> findAllOrderByName()
{
Session session = ((HibernateEntityManager)JPA.em()).getSession();
Criteria criteria = session.createCriteria(User.class);
criteria.setCacheable(true);
criteria.addOrder(Order.desc("name"));
return criteria.list();
}

This will basically cache the list of ids for the users and then get
each user from the cache and never hit the database. It will also
invalidate the query cache entry when a user is saved.

This obviously ties the code to a hibernate implementation, so I was
thinking of different ways on how to implement this better.

This is the inteface I was thinking of, basically augmenting the
JPAQuery class to implement setCacheable() simply relying on the
underlying hibernate query cache. JPAQuery is already tied to
hibernate at this point so I think structurally its no worse.

public static List<User> findAllOrderByName()
{
return User.find("order by name").setCacheable(true).fetch();
}

Thoughts?

Sorry for the long post :-)

Guillaume Bort

unread,
Dec 5, 2009, 7:55:51 AM12/5/09
to play-fr...@googlegroups.com
Hi,

> How do you think this would be best implemented? module?
> seperately? in the play.cache / play.db / play.data package?

I would implement it directly in play.db.jpa, right into the framework.

> Kinda sucks, as I don't think the JPA has any support for caching so
> we wouldn't have to be tied to the hibernate implementation being
> used. Any thoughts here?

No problem. Anyway for complex things you always need to rely on
Hibernate specific features.

> Thoughts?

You can post a bug report for that. I'm still not sure what is the
better way to do implicit caching. But you can try to start to work on
the 1.1 branch and then iterate.
> --
>
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>
>
>

Sport11can

unread,
Dec 6, 2009, 2:57:54 PM12/6/09
to play-framework
After looking at the memcached-hibernate code a little more I think a
different direction is best. Rather than duplicating his already
hibernate plugin, how about including the package in the play frame
lib directory and just using the "undocumented" configuration
"hibernate.memcached.memcacheClientFactory". This is currently how a
user is supposed to switch from using the spymemcached vs the
dangamemcached client. In the code the default is
"com.googlecode.hibernate.memcached.spymemcached.SpyMemcacheClientFactory",
a user just changes that to
"com.googlecode.hibernate.memcached.dangamemcached.DangaMemcacheClientFactory"
to switch cache providers. We only need the client factory
implementation of
com.googlecode.hibernate.memcached.MemcacheClientFactory and the
implementation of com.googlecode.hibernate.memcached.Memcache.

So to summarize I am suggesting that we just include this in the play
framework lib folder and have the default (commented out) play
hibernate configuration for caching to be
"hibernate.memcached.memcacheClientFactory=play.db.cache.CacheClientFactory"
and the cache implementation play.db.cache.CacheClient that will
merely just relay calls to play.cache.Cache.


How to abstract cacheable even though JPA doesn't

The only thing I can think of to abstract away specific hibernate
annotations is to create a Play! annotation play.db.cache.Cacheable
that people would use to indicate that this Model or relationship is
cacheable. Then in the JPA class loader
(play.classloading.enhancers.JPAEnhancer) find any Model or member
that has the play annotation on it and add the specific hibernate
annotation ie. @org.hibernate.annotations.Cache, and we would also
have to support maintaining the same annotation parameters
(CacheConcurrencyStrategy, region and include). This might be a cool
implementation if ever hibernate was replaced, the enhancer could just
be changed.


I still think augmenting play.db.jpa.JPASupport.JPAQuery to implement
the setCacheable(boolean) is the best interface for integrating the
query caching.
produces code like return User.find("order by name").setCacheable
(true).fetch(); which I think is very intuitive.


On Dec 5, 7:55 am, Guillaume Bort <guillaume.b...@gmail.com> wrote:
> Hi,
>
> > How do you think this would be best implemented?  module?
> > seperately?  in the play.cache / play.db / play.data package?
>
> I would implement it directly in play.db.jpa, right into the framework.
>
> > Kinda sucks, as I don't think the JPA has any support for caching so
> > we wouldn't have to be tied to the hibernate implementation being
> > used.  Any thoughts here?
>
> No problem. Anyway for complex things you always need to rely on
> Hibernate specific features.
>
> > Thoughts?
>
> You can post a bug report for that. I'm still not sure what is the
> better way to do implicit caching. But you can try to start to work on
> the 1.1 branch and then iterate.
>
>
>
> On Fri, Dec 4, 2009 at 11:06 PM, Sport11can <sport11...@gmail.com> wrote:
> > I have been playing with caching with hibernate within the Play!
> > framework.  There are 2 levels that what to talk about:
>
> > 1. Hibernate cache plugin:
>
> >        For now I have been usinghttp://code.google.com/p/hibernate-memcached/

Guillaume Bort

unread,
Dec 7, 2009, 3:01:57 AM12/7/09
to play-fr...@googlegroups.com
Seems good.

Apart for the the play specific @Cacheable annotation... I think that
we don't need to abstract Hibernate.

If you have some code contributions about that, feel free to create a
branch on launchpad and propose it for a merge.

Roman R

unread,
Aug 14, 2012, 7:34:45 AM8/14/12
to play-fr...@googlegroups.com
Hello,


Is it possible to configure hibernate cache to use memcached instead of Ehcache in Play 1.2.4?
Can't find any documentation or examples about this.
There's com.googlecode.hibernate.memcached library and you can configure it.

hibernate.cache.provider_class=com.googlecode.hibernate.memcached.MemcachedCacheProvider

But there's a problem that that memcached library has no RegionFactory. And Play 1.2.5 silently ignores this and keep using Ehcache.

And if memcached is not possible to integrate with Play 1.2.5,  is there any distributed cache solution that will work with Play? And it possible to find out how to do that, by documentation or examples?

Thank you!
Reply all
Reply to author
Forward
0 new messages