【问题标题】:Second level cache not working in Hibernate + Spring + JPA and EhCache二级缓存在 Hibernate + Spring + JPA 和 EhCache 中不起作用
【发布时间】:2016-09-09 13:10:15
【问题描述】:

让我清楚地了解二级缓存。我的 Web 应用程序的基类中有一个查询。几乎每一个动作都会调用这个查询(我正在使用 Struts,这就是应用程序的设计方式,所以不能真的搞砸它),例如加载我的主页会调用三个单独的 Struts 动作,并且这个查询会针对每个动作执行。 QueryDsl 形式的查询看起来像 Iterable<Event> eventsFromDb2 = eventRepository.findAll(EventExpressions.queryAllEvents()); 并以简化形式看起来Select e from Event e where e.deleted = false

这个查询需要大约 10 秒的甜蜜时间,因此它使应用程序非常慢,因为它调用了 Web 应用程序的每个操作(CRUD)。据我了解,在启用二级缓存时,hibernate+ Spring orm 应该从缓存中获取结果并避免数据库请求。但是,它不起作用。 persistence.xml 如下所示

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
                       http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
                       http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                       http://www.springframework.org/schema/tx
                       http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">



<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="flyway">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="de.mm.moreevent.type" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="false" />
            <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
            <property name="generateDdl" value="true" />
        </bean>
    </property>
<property name="jpaPropertyMap">
    <map>
        <entry key="hibernate.cache.use_query_cache" value="true" />
        <entry key="hibernate.cache.use_second_level_cache" value="true" />
        <entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
        <entry key="hibernate.cache.default_cache_concurrency_strategy" value="read-write" />
        <entry key="javax.persistence.sharedCache.mode" value="ALL" />
        <entry key="hibernate.generate_statistics" value="false" />
    </map>
</property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- see: http://springcert.sourceforge.net/2.5/4-study-transaction-management.html -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="makeBooking" read-only="false" propagation="NESTED" rollback-for="de.mm.moreevent.exception.ManagerException" />
        <tx:method name="sendConfirmationAndInvoice" read-only="true" propagation="NESTED" rollback-for="de.mm.moreevent.exception.ManagerException" />
        <tx:method name="sendConfirmationOnly" read-only="true" propagation="NESTED" rollback-for="de.mm.moreevent.exception.ManagerException" />
        <tx:method name="saveOrUpdate" read-only="false" propagation="NESTED" rollback-for="de.mm.moreevent.exception.ManagerException" />
        <tx:method name="participantsImport" read-only="false" propagation="NESTED" rollback-for="de.mm.moreevent.exception.ManagerException" />
    </tx:attributes>

</tx:advice>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <qualifier value="transactionManager" />
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- class="org.springframework.jdbc.datasource.DriverManagerDataSource" -->
    <property name="driverClass">
        <value>org.postgresql.Driver</value>
    </property>
    <property name="jdbcUrl">
        <value>jdbc:postgresql://127.0.0.1:port/dbName</value>
    </property>
    <property name="user">
        <value>user1</value>
    </property>
    <property name="password">
        <value>******</value>
    </property>
    <property name="initialPoolSize" value="5" />
    <property name="minPoolSize" value="5" />
    <property name="maxPoolSize" value="30" />
    <property name="idleConnectionTestPeriod" value="200" />
    <property name="acquireIncrement" value="1" />
    <property name="maxStatements" value="0" />
    <property name="numHelperThreads" value="3" />
</bean>

<!-- see: http://flywaydb.org/documentation/api.html  -->
<bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
    <property name="dataSource" ref="dataSource" />
     <property name="table" value="schema_version"></property>
     <property name="locations" value="customer/db-scripts/migration"/>
</bean>


<bean id="bouncyCastleProviderInitialisation" class="de.mm.moreevent.util.BouncyCastleProviderInitialisation" init-method="init" />

<bean id="strongEncryptorBC" class="org.jasypt.encryption.pbe.PooledPBEStringEncryptor">
    <property name="providerName">
        <value>BC</value>
    </property>
    <property name="algorithm">
        <value>algo</value>
    </property>
    <property name="password">
        <value>******</value>
    </property>
    <property name="poolSize">
        <value>4</value>
    </property>
</bean>

<bean id="hibernateStringEncryptor" class="org.jasypt.hibernate4.encryptor.HibernatePBEStringEncryptor">
    <property name="registeredName">
        <value>strongHibernateStringEncryptor</value>
    </property>
    <property name="encryptor">
        <ref bean="strongEncryptorBC" />
    </property>
</bean>

下面是Ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
     name="cacheManager"
     updateCheck="false"
     maxBytesLocalHeap="100M"
     statistics="true">

<!--
 | Please see http://ehcache.sourceforge.net/documentation    /configuration.html for
 | detailed information on how to configurigure caches in this file
 +-->
<!-- Location of persistent caches on disk -->
<diskStore path="java.io.tmpdir/moreEventObjCache" />

<defaultCache eternal="false" maxElementsInMemory="100000"
    overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="600"
    timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" statistics="true"/>

<cache name="bookingTransaktions" eternal="true"
    overflowToDisk="false" diskPersistent="false"
    timeToIdleSeconds="0" timeToLiveSeconds="0" statistics="true"/>

<cache name="mailingBean" eternal="true" maxElementsInMemory="10000"
    overflowToDisk="false" diskPersistent="false"
    />

以下是我的实体类

import javax.persistence.Cacheable;
...    
@Entity 
@Table(name = "EVENT")
@Cacheable
@Configurable(dependencyCheck = true)
public class Event extends MoreEventDataBaseEntity implements CloneChangeEventI {
...

我正在测试执行查询所花费的时间,以下是代码(我连续两次调用相同的查询)

    timer.mark();
    Iterable<Event> eventsFromDb = eventRepository.findAll(EventExpressions.queryAllEvents(), EventExpressions.orderByOnlineStartDate(true));
    timer.mark();
    Iterable<Event> eventsFromDb2 = eventRepository.findAll(EventExpressions.queryAllEvents(), EventExpressions.orderByOnlineStartDate(true));
    eventsFromDb2.getClass();
    timer.mark();

现在,在结果中,这段代码 sn-p 从网页调用了 3 次,下面是控制台中的结果

init Struts page load: 
EventManager.java:130: +0ms

// Query fired first time, it took 8 seconds as expected  
EventManager.java:132: +8103ms
// Query fired second time, it took 15 ms due to so caching
EventManager.java:135: +15ms

init (Ajax1):
EventManager.java:130: +0ms
// Query fired and it took 9.5 sec, However I am expecting it to be few milliseconds ???? second level cache not working I suppose ????   
EventManager.java:132: +9501ms
EventManager.java:135: +21ms
Before timer 2016-09-09T14:21:41.853+02:00

init (Ajax2): 
EventManager.java:130: +1ms
???? took 9.5 seconds again. second level cache not working I suppose same as Ajax1????
EventManager.java:132: +9506ms
EventManager.java:135: +22ms

同样的事情发生在整个应用程序中。二级缓存根本不起作用。如果我可以通过缓存节省此查询执行时间,这对我将有很大帮助。我正在使用 Spring ORM 3.2.1,Hibernate EhCache 4.1.9

【问题讨论】:

  • ehcache 配置在哪里?
  • 添加了 ehcache 配置
  • *.com/questions/10600698/… 此链接如何帮助您了解查询缓存。
  • @Huang 帮助不大
  • 一开始我只是想知道我对二级缓存的理解是否正确。

标签: hibernate jpa ehcache second-level-cache spring-orm


【解决方案1】:

二级缓存不起作用,因为您没有按 ID 获取数据(请参阅此链接 When and how to use hibernate second level cache?)。

在您的情况下,您可以使用查询缓存。

【讨论】:

    【解决方案2】:

    我认为你应该使用不同的区域工厂类:

    net.sf.ehcache.hibernate.EhCacheRegionFactory

    http://www.ehcache.org/documentation/2.7/integrations/hibernate

    另一方面,如果您使用 @Cacheable 注释,则必须使用 @EnableCaching

    启用它们
    <cache:annotation-driven />
    

    【讨论】:

    • 不幸的是,我使用的是旧版本的 hibernate 和 Ehcache。因此,教程中提到的一些属性对我来说并不适用。我想我必须先升级我的 Ehcache 和 Hibernate,然后再尝试该教程。此外,SAX 解析器为 &lt;cache name="com.somecompany.someproject.domain.Country" maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" &lt;persistence strategy="localTempSwap"/&gt; /&gt; 提供错误
    最近更新 更多