hibernate缓存
提高性能 的 方式 : 通过缓存 , 减少 与数据库 实际 发生交互的 次数
hibernate缓存 分类 : 一级缓存 ; 二级缓存 ; 查询缓存
(1) 一级缓存
该缓存为框架 默认自带的缓存 , 无需任何额外配置 即可使用
特点: 根据 对象ID 查询 到某个对象后, 再次查询 相同ID的对象, 直接从一级缓存中获取该对象, 不再 重复查询数据库
session关闭时, 会清除一级缓存对象
session.evict(obj) : 清除 单个对象的缓存
session.clear() : 清除所有缓存对象
(2) 二级缓存
特点: 需要做 额外配置, 缓存对象的 生命周期更长 , session关闭再重开, 缓存仍在
ehcache缓存配置:
1) 加入 相关jar包 , ehcache-1.2.3.jar,commons-logging-1.2.jar
2) 修改hibernate 框架 总配置文件
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 指定 二级缓存的 提供方 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
3) 再src 下 添加 ehcache.xml
可修改其中的 缓存策略
<cache> 的name属性与 实体类的全限定名对应, 否则 实体类对象将 采用默认的缓存策略
天
- 修改实体类映射文件 , 在 中加入 子元素
(3)查询缓存
注意 : 在配置了 二级缓存的基础上 使用 查询缓存
一级和二级缓存, 产生缓存的条件: 根据id 查询
查询缓存 , 产生缓存的 条件 : 重复执行 相同的 HQL语句, 批量查询
查询缓存的配置方法:
1) 修改 hibernate.cfg.xml
<property name="hibernate.cache.use_query_cache">true</property>
2) 调用 query的 方法 setCacheable(true)
注意: 查询缓存的 key 为 HQL语句 , HQL语句不同, 则 key不通, 所取到的 缓存内容也不通
from Emp where salary=? ==> 查询到 SCOTT
from Emp where salary >=? ==> 查询到 SCOTT
hql批量查询 方法 :
list() : 将 查询结果集 封装为 一个 List集合
iterate(): 返回一个针对于 查询结果集的 迭代器
list()和 iterate()对比:
(1) 底层SQL执行的方式不同,
list() 直接查询 HQL语句中 所查属性对应的 字段,一次获取所需结果集,SQL执行一次
iterate()先查询 主键列的值 , 在 循环迭代时,再 一次根据 主键列的各个值, 逐条 查询 结果集
假定符合条件结果集有n条,则SQL执行次数为: n+1 次
(2) 缓存的方式也不通
list() 直接 缓存 结果集内容
iterate() 将 迭代产生的 各个实体类对象 缓存 , 第二次执行查询时, 仍 查询主键列, 当迭代到某个 对象时,
会引用缓存对象
测试代码块:
package test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Test;
import entity.Emp;
import entity.Emp2;
import util.HibernateUtil;
public class TestCache {
/*该测试类测试 hibernate中的 缓存 机制*/
@Test
//测试一级缓存
public void testFirstCache(){
Session session = HibernateUtil.getSession();
Emp2 emp = (Emp2) session.get(Emp2.class,7788);//创建第一个对象 并查找条件
System.out.println(emp.getEname());//第一次结果 显示了sql语句
HibernateUtil.closeSession();
session = HibernateUtil.getSession();
System.out.println("============我是分割线============");
Emp2 emp2 = (Emp2) session.get(Emp2.class,7788); //创建第二个对象 并查找条件
System.out.println(emp.getEname());//第二次结果 没有显示sql语句,可见数据被一级缓存
}
//测试二级缓存
@Test
public void testSecondCache(){
Session session = HibernateUtil.getSession();
Emp2 emp = (Emp2) session.get(Emp2.class,7788);//创建第一个对象 并查找条件
System.out.println(emp.getEname());//第一次结果 显示了sql语句
HibernateUtil.closeSession();
session = HibernateUtil.getSession();
System.out.println("============我是分割线============");
Emp2 emp2 = (Emp2) session.get(Emp2.class,7788); //创建第二个对象 并查找条件
System.out.println(emp.getEname());//第二次结果 没有显示sql语句,可见数据被一级缓存
}
@Test
//测试 查询缓存
/*查询 缓存是建立在 二级缓存的基础上,当HQL语句相同时,触发查询缓存. 因HQL语句相同的 触发率太低,所以系统默认关闭
* 查询缓存,若想使用:
* 1.第一步则需在总配置文件中添加一个 使用 查询缓存的属性为 true
* 2.第二部则在代码块中引用query.setCacheable(true)方法
* 当HQL语句不完全相同时,不会触发查询 缓存*/
public void testQueryCache(){
Session session = HibernateUtil.getSession();
List<Emp2> list = session.createQuery("from Emp2").setCacheable(true).list();
for (Emp2 emp2 : list) {
System.out.println(emp2.getEname());
}
/*关闭会话后再打开会话,缓存依然存在,sql语句只执行一次*/
HibernateUtil.closeSession();
session = HibernateUtil.getSession();
System.out.println("============我是分割线============");
List<Emp2> list2 = session.createQuery("from Emp2").setCacheable(true).list();
for (Emp2 emp2 : list2) {
System.out.println(emp2.getEname());
}
}
}