Working example of Hibernate 3.6.2 2nd level cachi

2020-06-03 07:05发布

问题:

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 ?

回答1:

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.



回答2:

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 ?