In one of our use cases (that badly requires refactoring), we were suffering from a severe performance query degradation. We were querying for the same objects twice within the same hibernate session. While profiling the code we discovered that a majority of the time taken was by a single function
org.hibernate.intercept.FieldInterceptionHelper.extractFieldInterceptor() which we discovered was called whenever hibernate flushes the session.
What happens is that since neither individual queries nor the transaction is marked as read-only, hibernate checks each object in the session to see if any have been marked dirty and then flushes the session on the second query to ensure there are no dirty reads. Since these queries are being called in a loop, hibernate essentially flushes the session on every iteration resulting in what i am calling a “flush storm”.
The following posts led us to this conclusion.
There are a couple of solutions for this without rewriting the logic
1. Handle hibernate session flush manually and flushing the session at a lesser frequency.
2. If using Hibernate Query class, set Query.setReadOnly(true) for select queries so that on the second query, hibernate does not check for dirtiness and does not flush the session. Since we were not using the hibernate query object, we cannot use this solution however this maybe a viable solution for you.
3. Since we are using Spring’s HibernateTemplate.findByCriteria() we do not have a way to specify that a particular query is readOnly or not therefore the work around is to individually mark session objects as readonly so that hibernate does not check for dirtiness and flush unnecessarily. This is done via org.hibernate.session.setReadOnly(Entity,boolean) ..
As a test case, we went with option 1 and saw a marked improvement in performance however we eventually went with option 3.