一、JPA二级缓存
首先看下面的案例(没有配置二级缓存):
@Test
public void testSecondCache(){
Customer customer1 = entityManager.find(Customer.class, 3);
Customer customer2 = entityManager.find(Customer.class, 3);
}
使用上面的语句查询时会打印一条sql语句。
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.age as age2_0_0_,
customer0_.birth as birth3_0_0_,
customer0_.createDate as createDa4_0_0_,
customer0_.email as email5_0_0_,
customer0_.name as name6_0_0_
from
JPA_CUSTOMERS customer0_
where
customer0_.id=?
为什么会只打印一条sql呢?
原因是:JPA的一级缓存,属于Session级别的,在Session关闭的时候,一级缓存就失效了。
再看下面的实例:
@Test
public void testSecondCache(){
Customer customer1 = entityManager.find(Customer.class, 3);
transaction.commit();
entityManager.close();//查询完成后提交事务,关闭entityManager
//再次获取事务并开启
entityManager=entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction();
transaction.begin();
Customer customer2 = entityManager.find(Customer.class, 3);
}
打印的sql如下:
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.age as age2_0_0_,
customer0_.birth as birth3_0_0_,
customer0_.createDate as createDa4_0_0_,
customer0_.email as email5_0_0_,
customer0_.name as name6_0_0_
from
JPA_CUSTOMERS customer0_
where
customer0_.id=?
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.age as age2_0_0_,
customer0_.birth as birth3_0_0_,
customer0_.createDate as createDa4_0_0_,
customer0_.email as email5_0_0_,
customer0_.name as name6_0_0_
from
JPA_CUSTOMERS customer0_
where
customer0_.id=?
这次打印了两条sql语句,原因是使用的不是同一个entityManager。
二、JPA二级缓存的配置
第一步:首先在实体类上添加@Cacheable(true)注解
/**
*
*/
package com.jpa.helloword;
import java.util.Date;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.Cache;
/**
* @author 徐庶
* @date 2016年12月10日
*/
@Cacheable(true)
@Table(name="JPA_CUSTOMERS")
@Entity
public class Customer {
private Integer id;
private String name;
private String email;
private int age;
private Date birth;
private Date createDate;
@Temporal(TemporalType.DATE)
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Temporal(TemporalType.TIMESTAMP)
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@GeneratedValue(strategy=GenerationType.AUTO)
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", email=" + email
+ ", age=" + age + ", birth=" + birth + ", createDate="
+ createDate + "]";
}
}
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="JPA_1" transaction-type="RESOURCE_LOCAL">
<!-- 配置使用什么 ORM产品作为JPA的实现 -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- 添加持久化类 -->
<class>com.jpa.helloword.Customer</class>
<class>com.jpa.helloword.Order</class>
<!--
配置二级缓存的策略
<shared-cache-mode> 节点:若 JPA 实现支持二级缓存,该节点可以配置在当前的持久化单元中是否启用二级缓存,可配置如下值:
1.ALL:所有的实体类都被缓存
2.NONE:所有的实体类都不被缓存.
3.ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
4.DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
5.UNSPECIFIED:默认值,JPA 产品默认值将被使用
-->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<!-- 连接数据库配置 -->
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<!-- 配置JPA实现产品的配置 -->
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<!-- 二级缓存配置 -->
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"></property>
<property name="hibernate.cache.use_query_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>
添加ehcache.xml文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- diskStore 配置磁盘存储
path: 保存的路径
-->
<diskStore path="d:/ehcache"/>
<!-- defaultCache : 配置缓存细节
maxElementsInMemory : 二级缓存中,最大缓存对象的数量
eternal : 缓存的对象是否永久存储于内存中.
timeToIdleSeconds:(如果eternal配置为true.该配置无效.)对象在二级缓存中的最大空闲时间.
timeToLiveSeconds:(如果eternal配置为true.该配置无效.)对象在二级缓存中的最大存活时间.
overflowToDisk : 如果二级缓存中的对象超出了最大内存能容放的对象.是否溢出到硬盘上.
maxElementsOnDisk: 磁盘上最多能存放多少元素
diskPersistent : 在jvm关闭时,是否需要将内存中缓存的内容放入硬盘持久化.
diskExpiryThreadIntervalSeconds : 清理对象的轮询线程的轮询周期.
memoryStoreEvictionPolicy : 内存中对象超出了配置,移除策略是什么
Least Recently Used (specified as LRU). LRU(最近最少使用)
First In First Out (specified as FIFO) 可选的有LFU(最不常使用)
Less Frequently Used (specified as LFU) 和FIFO(先进先出)
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
配置完成后测试:
//JPA二级缓存的测试
@Test
public void testSecondCache(){
Customer customer1 = entityManager.find(Customer.class, 3);
transaction.commit();
entityManager.close();//查询完成后提交事务,关闭entityManager
//再次获取事务并开启
entityManager=entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction();
transaction.begin();
Customer customer2 = entityManager.find(Customer.class, 3);
}
打印sql如下:
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.age as age2_0_0_,
customer0_.birth as birth3_0_0_,
customer0_.createDate as createDa4_0_0_,
customer0_.email as email5_0_0_,
customer0_.name as name6_0_0_
from
JPA_CUSTOMERS customer0_
where
customer0_.id=?
至此,JPA的二级缓存测试完成