I am working on a simple example to illustrate my problem. It consists of two entities, (Contact and PhoneNumber) with a one-to-many relationship between them.
Contact -> PhoneNumbers
My application queries a set of contacts and their corresponding phone number using a set of complex queries. Once these have been retrieved I am going some further processing and navigate the relationship using phoneNumber.getContact quite a bit. The initial call to query all contacts and all phone numbers is done using:
Code:
List<Contact> contacts = (List<Contact>) em.createQuery("select c from Contact c where c.changeType != :changeType").setParameter("changeType", RecordType.DELETE).getResultList();
List<PhoneNumber> phoneNumbers = (List<PhoneNumber>) em.createQuery("select p from PhoneNumber p where p.changeType != :changeType").setParameter("changeType", RecordType.DELETE).getResultList();
I would have expected that the getContact call on PhoneNumber or getPhoneNumbers on Contacts would not result in further queries being executed against the database, however during profiling I found that it was queried again. This was killing the performance of my application. During my investigation I first tried to access the phone number from a constructed HashTable based on my previous result. However since PhoneNumber does not expose the Contact's primary key this didn't work.
My first question is : Is there a way to access the foreign key on the PhoneNumber table without reading the contact. This would allow me to access the contact in my own internal cache.
Then I read up on the cacheing options available and figured I give this a try. I added the following to persistence.xml
Code:
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.ejb.classcache.com.demo.Contact" value="read-only"/>
<property name="hibernate.ejb.classcache.com.demo.PhoneNumber" value="read-only"/>
as well as created ehcache.xml in my classpath:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir" />
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="300" overflowToDisk="true"/>
<cache name="com.demo.PhoneNumber" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
<cache name="com.demo.Contacts" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
</ehcache>
However this did not improve my problem at all. Maybe I am missing something, or maybe this is not the way it is supposed to work. Any suggestions on how I can avoid the second query to the database to fetch the Contacts I already fetched previously. I am doing both queries in the same transaction.
I am using the following versions:
Hibernate Annotations 3.4.0.GA
Hibernate 3.3.2.GA
Hibernate Commons Annotations 3.1.0.GA
Hibernate EntityManager 3.4.0.GA
Thanks in advance
Alex