三、二级缓存
1.1 二级缓存
因为一级缓存不能跨session存在,但是在多线程(同步)的情况下,可能会出现多个session需要共享同一份数据,为了避免频繁访问数据库,所以二级缓存应运而生!
因为二级缓存是由第三方供应商提供,所以在使用二级缓存的时候首先需要选择好使用哪一个提供商的二级缓存,并选择相应的支持包。
1.2 二级缓存策略提供商
这里需要注意的是,每个策略提供商所对应的类是不一样的,并且所支持的一些属性也不一样。
三、什么情况下能使用二级缓存
所以一般二级缓存中存放的对象需要满足以下三点:
1、该对象经常被访问
2、该对象不会被频繁改动
3、数据有限(数据不大)
例如:一个网站中,不同用户拥有不同的权限,此时这些权限信息就可以存放在二级缓存中
四、测试二级缓存
使用注解的方式使用二级缓存:@Cache
(1)在需要使用二级缓存的实体类上使用缓存注解:
<span style="font-size:14px;">@Entity
@Table(name="cache_users")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Users implements Serializable {
private static final long serialVersionUID = 1L;
private int id;// 用户ID
private String name;// 用户姓名
private String sex;// 用户性别
public Users() {
}
/**
* 带参构造器
* @param id
* @param name
* @param sex
*/
public Users(int id, String name, String sex) {
super();
this.id = id;
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode()) + "\nUsers [id=" + id + ", name=" + name + ", sex=" + sex + "]";
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
}</span>
除了注解指定对象存入二级缓存,也可以使用配置文件设置(见下面配置文件注释处)。
(2)在Hibernate配置文件中配置二级缓存
有几个地方必须要注意:
1、必须在配置中设置允许该项目使用二级缓存
2、必须指定所使用的cache版本的供应商的类,注意每个提供商提供的二级缓存的包是不一样的
hibernate.cfg.xml
<span style="font-size:14px;"><!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- session工厂,负责管理session -->
<session-factory name="foo">
<!-- 配置Oracle属性文件 -->
<!-- Hibernate方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- 配置驱动 -->
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<!-- 配置URL -->
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<!-- 配置用户名 -->
<property name="hibernate.connection.username">scott</property>
<!-- 配置密码 -->
<property name="hibernate.connection.password">root</property>
<!-- 是否显示SQL语句 -->
<property name="show_sql">true</property>
<!-- 设置是否产生关系表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 格式化SQL语句 -->
<property name="hibernate.format_sql">true</property>
<!-- 使用二级缓存前需要先在配置文件中允许使用 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 指定所使用的cache版本的供应商的类 -->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 查询缓存(依赖于二级缓存) -->
<property name="cache.use_query_cache">true</property>
<!-- 配置映射文件 -->
<!-- Users表的映射,注意,这里映射的是类 -->
<mapping class="com.entity.Users"/>
<!-- 如果不使用注解,就需要在此处指定二级缓存实体类 -->
<!--
<class-cache usage="read-write" class="com.entity.Users"/>
-->
</session-factory>
</hibernate-configuration></span>
(3)测试二级缓存
之前已经测试了,session级别的缓存不能跨session访问,所以不同的session之间是不能互相读取缓存中的数据。在这里,同样通过观察是否发送sql语句判断是否读取了缓存数据。
测试:
<span style="font-size:14px;">/*
* 测试2个session情况下,load延迟加载查询相同的数据的情况
* 通过控制台查看程序会向数据库发送几次查询语句
* 结果是只会发送一次,因为使用了二级缓存
*/
@Test
public void queryUsersDemo2(){
Session session1 = sf.openSession();//创建一个session
Users user1 = (Users) session1.load(Users.class, 22);//第一次查询
System.out.println(user1);//使用查询结果 System.out.println("============================");
Session session2 = sf.openSession();//创建二个session
Users user2 = (Users) session2.load(Users.class, 22);//第二次查询
System.out.println(user2);//使用查询结果
session1.close();
session2.close();
}</span>
测试结果:
<span style="font-size:14px;">Hibernate:
select
users0_.id as id0_0_,
users0_.name as name0_0_,
users0_.sex as sex0_0_
from
cache_users users0_
where
users0_.id=?
com.entity.Users@1e2dc906
Users [id=22, name=周怡, sex=女]
============================
com.entity.Users@56befa21
Users [id=22, name=周怡, sex=女]</span>
从上面的结果中可以观察到,即使使用的是不同的session,但是依然能读取到同一份数据。从发送sql的情况来看,第二个session读取数据时并没有到数据库中查询数据,而是使用缓存中的数据。