Hi everyone!
I experience very strange behaviour in Hibernate when using 1:1 relationsships with enabled query cache. Hibernate goes to database for the associated 1:1 children event though it has saved them in its cache!
First the mappings:
Code:
<class name="NjVenue"
table="T_VENUE" mutable="false">
<cache usage="read-only" region="Venue.Cache" />
<id name="techKey" column="TECHKEY">
<generator class="sequence">
<param name="sequence">SQ_VENUE_TECHKEY</param>
</generator>
</id>
<property name="marketCode" type="string">
<column name="MARKETCODE" length="2" />
</property>
<!-- implicitly using joining here -->
<one-to-one cascade="all" name="tradingDays"
class="NjTradingDays"
property-ref="parentVenue" />
Code:
<class name="NjTradingDays"
table="T_TRADINGDAYS" mutable="false">
<cache usage="read-only" region="TradingDays.Cache" />
<id name="techKey" column="TECHKEY">
<generator class="sequence">
<param name="sequence">SQ_TRADINGDAYS_TECHKEY</param>
</generator>
</id>
<many-to-one name="parentVenue" class="NjVenue"
column="VENUE"
unique="true" />
The query:Code:
List<NjVenue> myVenues = getCurrentSession().createCriteria(NjVenue.class)
//.setCacheable(true)
//.setCacheRegion("VenueDAO.findByMarketCode.Cache")
.add( Restrictions.eq("marketCode", "US") )
.list();
Query Cache is not used, everything's fine. Hibernate does a join and gets all venues and tradingdays entities:
Code:
<2008-04-17 17:04:57,625>
select
this_.TECHKEY as TECHKEY5_1_,
this_.MARKETCODE as MARKETCODE5_1_,
njtradingd2_.TECHKEY as TECHKEY7_0_,
njtradingd2_.VENUE as VENUE7_0_
from
T_VENUE this_,
T_TRADINGDAYS njtradingd2_
where
this_.TECHKEY=njtradingd2_.VENUE(+)
and this_.MARKETCODE=?
After committing and re-excuting the query in the next transaction, behavior stays the same.
Now I enable the Query Cache:Code:
List<NjVenue> myVenues = getCurrentSession().createCriteria(NjVenue.class)
.setCacheable(true)
.setCacheRegion("VenueDAO.findByMarketCode.Cache")
.add( Restrictions.eq("marketCode", "US") )
.list();
The first execution does the expected join thus reading and caching all venues and tradingdays:
Code:
<2008-04-17 18:35:36,296>
select
this_.TECHKEY as TECHKEY5_1_,
this_.MARKETCODE as MARKETCODE5_1_,
njtradingd2_.TECHKEY as TECHKEY7_0_,
njtradingd2_.VENUE as VENUE7_0_
from
T_VENUE this_,
T_TRADINGDAYS njtradingd2_
where
this_.TECHKEY=njtradingd2_.VENUE(+)
and this_.MARKETCODE=?
<2008-04-17 18:35:36,562> Caching: NjTradingDays#2303
<2008-04-17 18:35:36,578> Caching: NjVenue#3
After committing this transaction and re-executing the query in the next transaction, funny things happen:
Code:
<2008-04-17 18:35:39,218> checking cached query results in region: VenueDAO.findByMarketCode.Cache
<2008-04-17 18:35:39,218> key: sql: select this_.TECHKEY as TECHKEY5_1_, this_.MARKETCODE as MARKETCODE5_1_, njtradingd2_.TECHKEY as TECHKEY7_0_, njtradingd2_.VENUE as VENUE7_0_ from T_VENUE this_, T_TRADINGDAYS njtradingd2_ where this_.TECHKEY=njtradingd2_.VENUE(+) and this_.MARKETCODE=?; parameters: US,
<2008-04-17 18:35:39,218> Checking query spaces for up-to-dateness: [T_VENUE]
<2008-04-17 18:35:39,218> key: T_VENUE
<2008-04-17 18:35:39,218> Element for T_VENUE is null
<2008-04-17 18:35:39,218> returning cached query results
<2008-04-17 18:35:39,218> key: NjVenue#3
<2008-04-17 18:35:39,218> Cache hit: NjVenue#3
<2008-04-17 18:35:39,218>
select
njtradingd0_.VENUE as VENUE7_0_
from
T_TRADINGDAYS njtradingd0_
where
njtradingd0_.VENUE=?
<2008-04-17 18:35:39,218> Caching: NjTradingDays#2303
While Hibernate is fetching the Venue from cache, it does hit the database AGAIN for the TradingDays entity, even though it was cached before! It just overwrites the cached entity with the newly read.
Switching to fetch="select"I read somewhere that there are issues with joined fetching (as above) and 2nd level cache usage, so I gave fetchmode:select a chance:
Code:
<class name="NjVenue" ...
(ommiting unchanged part)
<!-- now using select fetching -->
<one-to-one cascade="all" name="tradingDays" fetch="select"
class="NjTradingDays"
property-ref="parentVenue" />
The first execution (cache is empty) works as expected, Hibernate fetches the Venue and subsequently the TradingDays entities, then caches both:
Code:
<2008-04-17 18:49:30,187> checking cached query results in region: VenueDAO.findByMarketCode.Cache
<2008-04-17 18:49:30,187> key: sql: select this_.TECHKEY as TECHKEY5_0_, this_.MARKETCODE as MARKETCODE5_0_ from T_VENUE this_ where this_.MARKETCODE=?; parameters: US,
<2008-04-17 18:49:30,187> Element for sql: select this_.TECHKEY as TECHKEY5_0_, this_.MARKETCODE as MARKETCODE5_0_ from T_VENUE this_ where this_.MARKETCODE=?; parameters: US, is null
<2008-04-17 18:49:30,187> query results were not found in cache
<2008-04-17 18:49:30,187>
select
this_.TECHKEY as TECHKEY5_0_,
this_.MARKETCODE as MARKETCODE5_0_
from
T_VENUE this_
where
this_.MARKETCODE=?
<2008-04-17 18:49:30,500>
select
njtradingd0_.TECHKEY as TECHKEY7_0_,
njtradingd0_.VENUE as VENUE7_0_
from
T_TRADINGDAYS njtradingd0_
where
njtradingd0_.VENUE=?
<2008-04-17 18:49:30,515> Caching: NjTradingDays#2303
<2008-04-17 18:49:30,515> Caching: NjVenue#3
After committing and re-executing in the next transaction, Hibernate gets the Venue from cache but again,
NOT the associated TradingDays entitiy:
Code:
<2008-04-17 18:49:33,125> checking cached query results in region: VenueDAO.findByMarketCode.Cache
<2008-04-17 18:49:33,125> key: sql: select this_.TECHKEY as TECHKEY5_0_, this_.MARKETCODE as MARKETCODE5_0_ from T_VENUE this_ where this_.MARKETCODE=?; parameters: US,
<2008-04-17 18:49:33,125> Checking query spaces for up-to-dateness: [T_VENUE]
<2008-04-17 18:49:33,125> key: T_VENUE
<2008-04-17 18:49:33,125> Element for T_VENUE is null
<2008-04-17 18:49:33,125> returning cached query results
<2008-04-17 18:49:33,125> key: NjVenue#3
<2008-04-17 18:49:33,125> Cache hit: NjVenue#3
<2008-04-17 18:49:33,125>
select
njtradingd0_.TECHKEY as TECHKEY7_0_,
njtradingd0_.VENUE as VENUE7_0_
from
T_TRADINGDAYS njtradingd0_
where
njtradingd0_.VENUE=?
<2008-04-17 18:49:33,125> Caching: NjTradingDays#2303
Hibernate does not even try to query the cache for the associated entities!
My ehcache.xml settings are as follows:
Code:
<defaultCache
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
/>
Code:
<cache name="Venue.Cache"
maxElementsInMemory="150"
eternal="true"
overflowToDisk="false"
/>
Code:
<cache name="TradingDays.Cache"
maxElementsInMemory="150"
eternal="true"
overflowToDisk="false"
/>
Code:
<cache name="VenueDAO.findByMarketCode.Cache"
maxElementsInMemory="200"
eternal="true"
overflowToDisk="false"
/>
What am I missing here? Why can't I get Hibernate to cache the associated entities? Is it a Hibernate bug?
Is the problem that the join field T_TRADINGDAYS.VENUE is not the primary key (the surrogate key TECH_KEY is PK)?
I'd greatly appreciate any help on this. This is already causing trouble in another project using hibernate as well...
Hibernate version: 3.1.2
EHCache version: 1.1