JPA学习 —— 第十三课、使用二级缓存

一级缓存

一级缓存是session级别的缓存,在JPA中一个entityManager对应一个session,一个session就对应一个缓存。

查询两次id为1的user

User user1 = entityManager.find(User.class, 1);
User user2 = entityManager.find(User.class, 1);

结果发现只调用了一次sql查询,因为使用了一级缓存,当第一次find就把查询到的数据放入到还缓存中,第二次再查会先去缓存中找,如果有就直接使用而不用重新查询。
JPA学习 —— 第十三课、使用二级缓存_第1张图片

如果查询一次后,关掉entityManager,再查询

User user1 = entityManager.find(User.class, 1);
entityManager.close();
entityManager = factory.createEntityManager();
User user2 = entityManager.find(User.class, 1);

发现查询了两次,因为entityManager关闭之后,其对应的缓存也就没有了。
然后有重新开启一个entityManager,就和之前的不是同一个了。
JPA学习 —— 第十三课、使用二级缓存_第2张图片

配置二级缓存

如果说一级缓存是关联session级别的局部缓存,那么二级缓存就是全局缓存。
可以跨entityManager的缓存,也就是说:就算你关闭了entityManager,缓存也依然在。

在配置文件applicationContext.xml中配置


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    
    <context:property-placeholder location="classpath:jdbc.properties" />

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}">property>
        <property name="password" value="${jdbc.password}">property>
        <property name="driverClass" value="${jdbc.driverClass}">property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}">property>
        
    bean>

    
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource">property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">bean>
        property>
        <property name="packagesToScan" value="com.ssj.domain">property>

        <property name="jpaProperties">
            <props>
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategyprop>
                
                <prop key="hibernate.hbm2ddl.auto">updateprop>
                
                <prop key="hibernate.show_sql">trueprop>
                
                <prop key="hibernate.format_sql">trueprop>
                
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialectprop>
                
                <prop key="hibernate.cache.use_second_level_cache">trueprop>
                <prop key="hibernate.cache.use_query_cache">trueprop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory
                prop>
                <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache.xmlprop>
            props>
        property>
        
        <property name="sharedCacheMode" value="ENABLE_SELECTIVE">property>

    bean>
beans>

注:有两个地方需要配置,一个是开启二级缓存,一个是配置缓存策略。

使用二级缓存需要添加以下依赖:

<dependency>
    <groupId>org.hibernategroupId>
    <artifactId>hibernate-ehcacheartifactId>
    <version>${hibernate.version}version>
dependency>

其实还有ehcache-core的jar包,只是在使用hibernate-ehcache整合jar包会使用到ehcache-core的jar包,在引入这个依赖时自动添加进去了。

在resources文件夹下加入一个配置文件:ehcache.xml,这个文件直接拷贝来用就行了,不用理会里面的内容,有需要的时候再研究也不迟



    -- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    "java.io.tmpdir"/>


    --Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
    "10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    --Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required for defaultCache:

        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->

    -- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    "
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    
    "
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

    

使用二级缓存

第一种方法
1.在实体类上加注解@Cacheable(true)

@Cacheable(true)
@Table(name="user")
@Entity
public class User ...

2.在配置文件applicationContext.xml中配置二级缓存的策略
这个上面已经配置过了


<property name="sharedCacheMode" value="ENABLE_SELECTIVE">property>

再次执行

User user1 = entityManager.find(User.class, 1);

entityManager.close();
entityManager = factory.createEntityManager();

User user2 = entityManager.find(User.class, 1);

结果只调用了一次sql查询语句,说明二级缓存 起作用了。
第二种方法:
第二种方法是使用@Cache + @Cacheable 组合

@Entity  
@Table(name ="tablename")  
@Cacheable  
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)  
public class XxxEntity{}  

当使用了@Cache注解后就不需要配置二级缓存策略了:

<property name="sharedCacheMode" value="ENABLE_SELECTIVE">property>

使用@Cache注解与上面配置相当

集合缓存

就是二级缓存的一种

@Entity 
@Table(name =”parent”) 
@Cacheable 
public class Parent{
private static final long serialVersionUID = 1L;  
private String name;  
private List clist;  

public String getName() {  
    return name;  
}  
public void setName(String name) {  
    this.name = name;  
}  

@OneToMany(fetch = FetchType.EAGER,mappedBy = "parent")  
    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)  
public List getClist() {  
    return clist;  
}  
public void setClist(List clist) {  
    this.clist = clist;  
}  
}

在一对多关连关系的集合属性上设置二级缓存,在关连查询的时候就可以使用缓存了。

使用hibernate的query查询缓存

一,二级缓存都是根据对象id来查找,如果需要加载一个List的时候,就需要使用Query 进行查询,这里就用到了查询缓存。

String jpql = "FROM User u WHERE u.id = ?";
Query query = entityManager.createQuery(jpql);
query.setParameter(1, 1);
User user = (User) query.getSingleResult();

query = entityManager.createQuery(jpql);
query.setParameter(1, 1);
user = (User) query.getSingleResult();

很显然会执行两次查询
JPA学习 —— 第十三课、使用二级缓存_第3张图片
虽然说是使用的同一个session查询同一条数据,但是这里却没有像上面find那样使用缓存。
如果想要使用缓存,只查询一次,可以使用setHint

String jpql = "FROM User u WHERE u.id = ?";
Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
query.setParameter(1, 1);
User user = (User) query.getSingleResult();

query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
query.setParameter(1, 1);
user = (User) query.getSingleResult();

可以看到值查询了一次
JPA学习 —— 第十三课、使用二级缓存_第4张图片
query查询缓存能够使用需要之前开启的二级缓存配置的,主要是配置了:

<prop key="hibernate.cache.use_query_cache">trueprop>

spring Data jpa 查询缓存

需要配置:

<prop key="hibernate.cache.use_query_cache">trueprop>  

在方法内打上@QueryHint来实现查询缓存

@Query("from XxxEntity")  
@QueryHints({ @QueryHint(name = "org.hibernate.cacheable",value ="true") })  
List findAllCached();

注意: 这样查询缓存是不会生效的,也就是spring-data-jpa默认实现的findAll()方法无法保存到查询缓存

@QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) 
List findAll(); 

你可能感兴趣的:(JPA)