[hibernate-dev] 2nd-level cache suggestions

Alex Besogonov cyberax at staffdirector.net
Mon Mar 31 21:29:32 EDT 2008


Good <time-of-day>!

I'm writing a custom "lazy materialized" multimap collection for 
Hibernate. The main reason I'm doing this is that I want to use 
2nd-level cache.

So far, I've found several problems with the way caching is implemented 
in Hibernate:

1. Collections are not cached unless they are completely initialized. 
That kind of kills the possibility of cached extra lazy collections.

2. Collection loading can be VERY slow. The "initializeFromCache" method 
of the built-in Hibernate collections looks something like:
========
	public void initializeFromCache(CollectionPersister persister, 
Serializable disassembled, Object owner)
	throws HibernateException {
		Serializable[] array = ( Serializable[] ) disassembled;
		int size = array.length;
		beforeInitialize( persister, size );
		for ( int i = 0; i < size; i++ ) {
			list.add( persister.getElementType().assemble( array[i], 
getSession(), owner ) );
		}
	}
========
If the collection elements are pushed out of the cache (and its a quite 
probable situation with large collections) - we'll have N+1 selects problem.

3. Mass operations API for caches is not used in Hibernate. Some caches 
support bulk loading APIs (usually in forms like 'getAll(Collection 
keys)'). We can greatly speedup the 2nd-level caches by using these APIs 
(when available, of course).





I propose the following solutions:

1. I think it's possible to add a manual collection cache entry update 
in the postAction() callback. And it'll probably work.

2. This one is much harder to fix. I'm planning to add a special flag 
"onlyCached" to the LoadEvent and add the corresponding functionality to 
the DefaultLoadEventListener. So I'll have something like:
========
	public void initializeFromCache(CollectionPersister persister, 
Serializable disassembled, Object owner)
	throws HibernateException {
		Serializable[] array = ( Serializable[] ) disassembled;
		int size = array.length;
		Object [] loaded=new Object[size];
		List notInCache=new ArrayList();

		beforeInitialize( persister, size );

		for ( int i = 0; i < size; i++ ) {
			loaded[i]=session.tryToLoadFromCache(array[i], owner);
			if (loaded[i]==null)
				notInCache.add(array[i]);
		}

		Iterator entities=getSession().createCriteria(
			persister.getElementType().getName())
			.add(Restrictions.in("id",notInCache))
			.iterate();
		for(int i=0; i < size; i++)
		{
			if (loaded[i]!=null)
				list.add(loaded[i]);
			else
				list.add(entities.next());
		}
	}
========

3. This is a fairly large task, which requires changing some of 
Hibernate fundamentals (like LoadEvent). But I think I can do it.





Any thoughts? Am I stupidly missing some obvious flaw?


-- 
With respect,
             Alex Besogonov (cyberax at staffdirector.net)



More information about the hibernate-dev mailing list