5

I have many to one relation, let's say User has a Company. Company entity does not have any other relations.

If I enable second level cache for findAll hibernate query of Company, the second time I reload page (which means that User is loaded and then also list of all Companies is loaded) I get select for each existing company (select ... from company where id=?) in hibernate output. This happens when calling findAll for Company, it looks like this (this is generic method in class which is extended with appropriate type):

return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {

            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria c = session.createCriteria(persistentClass);
                c.setCacheable(cacheFindAll);

                return c.list();
            }
        });

I am using Jboss TreeCacheProvider in read-only strategy. If I use setCacheable(false) there are no "unwanted" selects.

Why is this happening and how can I eliminate this behavior?

1 Answer 1

7

The call setCacheable() is for enabling the query cache, see javadoc:

Enable caching of this query result, provided query caching is enabled for the underlying session

What happens is that the ids of the companies are cached but not the objects itself. If you enable the second level cache these individual company queries will be handled by the second level cache.

In order to enable second level cache you need to set the hibernate.cache.use_second_level_cache=true in the persistence.xml. Also you need to annotate you’re relations and entities you like to cache in the second level cache.

@OneToMany
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private List<Company> companies;

And entity caching:

@Entity
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Company {
    ...
}

BTW the second level cache will only cache relations and entities you find on id. Queries can't be cached by the second level cache and will always go to the database (or query cache).

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, yes, you are right setCacheable sets the query cache. However I still do not understand why there are multiple selects happening. They are only happening when setCacheable(true) and second level cache is set to read-only, when I set it to transactional it does not happen. I also tried EHcache in read-write and it does not happen. Also, is there a way to cache entities which I need to load all? (Such as country list, etc.)
If you do an EntityManager.createQuery("from Company").getResultList(); you will have all your companies in your second level cache. Then if you make sure that you have made all relations to company lazy loading and you don’t refer to companies in your queries, then they will always be read from second level cache (that is, if you don’t let the cache expire or overflow).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.