Quick Version
Basically, I'm updating a Hibernate Table and subsequent queries are loading a stale value.
Detailed Version
Hibernate (3.3.1.GA) and EhCache (2.4.2).
Persisted Book
object with a List<PageContent>
of pages and I'm adding a page to the middle of this book. I'm using Databinder/Wicket, though I do not think that is related.
public void createPageContent(Book book, int index) {
Databinder.getHibernateSession().lock(book, LockMode.UPGRADE);
PageContent page = new PageContent(book);
book.addPage(page, index);
CwmService.get().flushChanges(); // commits the transaction
}
The applicable fields/method in Book
are:
@OneToMany
@JoinColumn(name="book_id")
@IndexColumn(name="pageNum")
@Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
private List<PageContent> pages = new ArrayList<PageContent>();
public synchronized void addPage(PageContent page, int index) {
pages.add(index, page);
}
The end result is that there is a new page added to a list and the database is updated accordingly and I've confirmed this in my datastore. However, the next query for a page, say "Page #4," loads the "old" Page #4 instead of the new Page #4:
criteria.add(Restrictions.eq("book", book));
criteria.add(Restrictions.eq("pageNum", pageNum));
criteria.setCacheable(true);
So, I grudgingly remove caching from the criteria. It queries the datastore, but still returns the wrong value. However, in both cases, if I wait about 2 minutes, everything is working as expected. I presume caching is still involved. Both PageContent
and Book
use this caching strategy:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
I confess I'm new to caching and just set up this file for the first time. Here's my ehcache.xml:
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="false"/>
<!-- Hibernate's Cache for keeping 'lastUpdated' data on each table. Should never expire. -->
<cache name="org.hibernate.cache.UpdateTimestampsCache" eternal="true" />
<!-- Hibernate's Query Cache - should probably be limited -->
<cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="1000" />
UPDATE: Removing the @Cache
annotations on my datastore objects removes the problem. Of course, I would like to cache these objects because page modification is much less frequent than access.
So, thoughts? There are several other issues related as well, including with deleting pages. Everything updates the database as expected, but actual behavior is wonky.
Thanks in advance!
UPDATE #2: Via debugging, I can confirm that the Datastore has the correct information and when the query runs, it falls back on the Second-Level Cache - which has dirty information. I presume it's not up to me to evict from the cache every time the data changes?