JPA + Hibernate + EHCache, unexpected behavior
ehcache, hibernate, jakarta-ee, java, jpa
Solution
Hibernate will never execute queries on your cache. What it can do is execute a query on the database, cache the results, and return these cached results the next time you execute the same query, with the same parameters. But to do that, the query, each time it's executed, must be cacheable.
WIth the JPA API, this is done using query hints, directly on the named query definition, or each time you create a query:
@NamedQuery(name = "Cars.findAll",
query = "SELECT d FROM Cars d",
hints = {@QueryHint(name = "org.hibernate.cacheable", value = "true")})
Now that the query is cacheable, Hibernate will load the IDs of the cars from the database the first time this query is executed, and from the query cache afterwards. Then the corresponding cars themselves will be loaded from the entity cache.
Problem
I'm trying to implement EHCache into my working prototype, where I have a javax.persistence.Entity representing a table on my database (MySQL, mysql-connector-java-5.1.20.jar), which be provided as XML to the consumers. The issue I'm facing is that seems Hibernate still retrieving the data from the database, even when EHCache stores the query result on memory. I'm using the EHCache monitor to see the count of items in memory, and changing the data directly on database before the cache expires to know if the cached data is actually used. I been looking for a replication for this issue without succeed, so maybe I'm missing something (I just geting into the java world). My files pom.xml ``` <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.3.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.1.4.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>4.1.4.Final</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>org.terracotta</groupId> <artifactId>ehcache-probe</artifactId> <version>1.0.2</version> </dependency> ``` Entity class ``` package myPrototype.entities import javax.persistence.Cacheable; import javax.persistence.Entity; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; import javax.xml.bind.annotation.XmlRootElement; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @Entity @Cacheable @Cache(usage=CacheConcurrencyStrategy.READ_ONLY) @Table(name = "Cars") @XmlRootElement @NamedQueries({ @NamedQuery(name = "Cars.findAll", query = "SELECT d FROM Cars d"), [...] public class Cars implements Serializable { private static final long serialVersionUID = 1L; @Basic(optional = false) @NotNull @Column(name = "id") @ReferenceField private int id; [...] ``` ehcache.xml ``` <?xml version="1.0" encoding="UTF-8"?> <ehcache> <cache name="myPrototype.entities.Cars" maxElementsInMemory="500" eternal="false" overflowToDisk="false" timeToIdleSeconds="60" timeToLiveSeconds="120" /> </ehcache> ``` * I tried setting eternal="true", but the result still the same persistence.xml ``` <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="MyPrototype" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:app/jdbc/mysqlserver/prototype</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> <properties> <!-- property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/ --> <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" /> <property name="hibernate.cache.use_second_level_cache" value="true"/> <property name="hibernate.cache.use_query_cache" value="true"/> <property name="hibernate.cache.region_prefix" value=""/> </properties> </persistence-unit> </persistence> ``` * I tried switching between SingletonEhCacheRegionFactory and EhCacheRegionFactory EJB ``` import myPrototype.entities.Cars import java.util.Date; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @Stateless public class CarsEJB { @PersistenceContext(unitName="MyPrototype") private EntityManager em; @Override public List<Cars> getCars() { return (List<Cars>)em.createNamedQuery("Cars.findAll").setMaxResults(200).getResultList(); } } ``` * Added to clarify how I run the query Like I said, I can see a count of items in memory through EHCache monitor, so I noted the following: - The ehcache configuration is property loaded elements are expiring - The elements expiration not being reseted when the query runs while they still alive (they expired N seconds after the first query). Again; I'm quite a newbie with java, so asume I could be missing basic concepts. Thanks for reading!