Working example of Hibernate 3.6.2 2nd level caching with JPA2?

12,917

Solution 1

Found the culprit - although it's pretty counter-intuitive:

Queried entities are not put into the second-level cache unless you close the session/entity manager. Even if you requery with the very same objects, still no caching will happen.

I have a long batch process in which many reference objects are created and reused. If I keep the same entity manager all along, I don't see the end of the process. If I recreate the entity manager at each cycle, the application flies.

I thought there was something like a 1st level cache - the persistence context ?

Solution 2

One of my project uses ehcache + hibernate + jpa2. I tell you my configuration. Hope it helps you.

framework versions (maven dependency):

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <!-- <version>3.6.2.Final</version> -->
    <version>4.0.0.Alpha1</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <!-- <version>3.6.2.Final</version> -->
    <version>4.0.0.Alpha1</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>javax.persistence</artifactId>
    <version>2.0.0</version>
</dependency>
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>2.3.1</version>
    </dependency>

The two hibernate versions are tested, but I don't use the hibernate jpa2 api.

persistence.xml:

<persistence-unit name="UNIT" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <non-jta-data-source>java:/comp/env/ds</non-jta-data-source>
    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    <properties>
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="false" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>

        <!-- 2nd level cache -->
        <property name="hibernate.cache.provider_class"
            value="net.sf.ehcache.hibernate.SingletonEhCacheProvider"/>
        <property name="net.sf.ehcache.configurationResourceName"
            value="/ehcache.xml" />
        <property name="hibernate.cache.use_query_cache" value="true" />
        <property name="hibernate.cache.use_second_level_cache"
            value="true" />
        <property name="hibernate.generate_statistics" value="false" />
    </properties>
</persistence-unit>

ehcache.xml:

<ehcache updateCheck="false">

    <diskStore path="java.io.tmpdir" />

    <defaultCache maxElementsInMemory="10000" eternal="false"
        statistics="true" timeToIdleSeconds="120" timeToLiveSeconds="120"
        overflowToDisk="true" diskPersistent="false" 
        diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />

    <cache name="com.yourcompany.CachedEntity" eternal="true"
        maxElementsInMemory="1000" />                       
</ehcache>

Finally you should annotate your cachable entity class. Here is an example:

package com.yourcompany;
@Entity
@Table(name="cached_entity")
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class CachedEntity implements Serializable {
}

This configuration works for me, hope it was useful.

Share:
12,917
Jan Goyvaerts
Author by

Jan Goyvaerts

Updated on July 05, 2022

Comments

  • Jan Goyvaerts
    Jan Goyvaerts almost 2 years

    The title obviously states it : I can't make the second-level cache work for JPA2/Hibernate 3.6.3.

    I've been trying many a hack to make it work. But I'm only succeeding in having the query cache working. Although Hibernate creates the caches (name of the instance), they're ignored. Even misses are not registered. Maybe it's a version incompatibility. I've tried some others with no result. And I don't feel up to the task anymore to try all permutations. :-P

    I'm asking the question here as some people seem to have it working (whose examples I tried also). Maybe they can spot the obvious error I'm making.

    Thanks in advance for anybody helping me out ! :-)

    persistence.xml

    <persistence 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"
             version="2.0">
    
    <persistence-unit name="foo" transaction-type="RESOURCE_LOCAL">
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:/opt/db/foo;create=true"/>
            <property name="javax.persistence.jdbc.user" value="foo"/>
            <property name="javax.persistence.jdbc.password" value="bar"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory"/>
            <property name="hibernate.cache.use_second_level_cache" value="true"/>
            <property name="hibernate.cache.use_query_cache" value="true"/>
        </properties>
    </persistence-unit>
    

    pom.xml

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.6.3.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
        <version>2.4.2</version>
    

    JMX setup

    This way I can check the usage of the caches. The caches are created (one for each entity) and the two query caches are there too. The latter are filling up pretty fast. But none of the caches display any misses or hits. Not even the query caches.

     ManagementService.registerMBeans( CacheManager.getInstance(), ManagementFactory.getPlatformMBeanServer(), true, true, true, true, true )
    

    The entity caches are ignored. They should contain at least the entities that are saved into the database. Or being retrieved with queries. Nothing moves there.

    Sample Java code

    EntityManager entityManager = Persistence.createEntityManagerFactory("foo").createEntityManager();
    entityManager.getTransaction.begin();
    entityManager.merge(bar);
    entityManager.getTransaction.commit();   
    
    Query query = entityManager.createQuery("select b from Bar p where b.name = :name");
    query.setParameter("name", "fooBar");
    query.setHint("org.hibernate.cacheable","true");
    query.getSingleResult();
    

    The merge works - because there's data into the database. And the find works because I'm getting objects with generated id's.

    The queried entities are indexed on the database.

    WHODUNNIT ?

  • Jan Goyvaerts
    Jan Goyvaerts almost 13 years
    Thank you ! I'll have a try with it asap. In the meantime, the only noticeable difference I see is that the entity is Serializable. Is that a requirement now ?
  • lepike
    lepike almost 13 years
    I think here you can find the answer. stackoverflow.com/questions/2020904/…
  • Jan Goyvaerts
    Jan Goyvaerts almost 13 years
    The provided example here works, but the entities are not cached when persisting. Only when being queried. Is that the way it is meant to work ?
  • lepike
    lepike almost 13 years
    I think this means only query cache. I don't know how can you cache the entities for persist. If you use batchinsert or batchupdate, the jdbc driver will manage this kind of cache for you.