Hibernate中提供了两个级别的缓存:
一级缓存是session的缓存,它属于session的生命周期,session关闭后缓存也将清除.这就说明用session来提升性能的能力有限,而二级缓存是sessionFactory级别的,可以做更多的事情,但是默认是不开启的,我们想要使用,就必须先开启.在主配置文件中添加以下代码来开启二级缓存:
<property name="cache.use_second_level_cache">true</property>
光开启还不够,还要提供二级缓存的实现,需要给定缓存的提供商,有多种提供商可供选择,EhCacheProvider是一个专业的缓存提供商,在这里就使用它为hibernate的二级缓存服务.给出配置文件的相关配置:
<ehcache>
<!-- 在内存中存不下的时候,存放的临时目录 -->
<diskStore path="c:/ehcache"/>
<!--
maxElementsInMemory:可存10000个对象,超出后存入临时目录
eternal:设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false
timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。
如果此值为0,表示对象可以无限期地处于空闲状态。
timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。
如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值
overflowToDisk:设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
到此才算是完全开启,但是,光开启还不够!需要指定哪些类需要缓存,不需要的就不指定.如果有哪个类更新频率很快,比如新闻、首页之类的,就不需要缓存.把类缓存起来称为类缓存.
<class-cache usage="read-write" class="..senondcache.Department"/>
<class-cache usage="read-write" class="..senondcache.Employee"/>
二级缓存中的类缓存,只适用于使用id查询的方式,比如get()或load(),对于使用HQL的方式不可以缓存,比如"FROM Department d WHERE d.id=1"就不会缓存,比如以下就可以缓存:
@Test
public void testSecondCache() {
// ==========================================================
// 第一个Session
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// --------------------------------------------------------------
Department department = (Department) session.get(Department.class, 1);
System.out.println(department);
System.out.println(department.getEmployees());
// --------------------------------------------------------------
tx.commit();
session.close();
System.out.println("/n----------/n");
// ==========================================================
// 第二个Session
session = sessionFactory.openSession();
tx = session.beginTransaction();
// --------------------------------------------------------------
Department department2 = (Department) session.get(Department.class, 1);
System.out.println(department2);
System.out.println(department2.getEmployees());
// --------------------------------------------------------------
tx.commit();
session.close();
}
如果想使用查询缓存,还要在主配置文件中打开"开关":
<property name="cache.use_query_cache">true</property>
但是这样还不够,没有缓存哪条语句,在程序中指定:
@Test
public void testQueryCache() {
// ==========================================================
// 第一个Session
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// --------------------------------------------------------------
Department department = (Department) session.createQuery(//
"FROM Department d WHERE d.id=?")//
.setParameter(0, 1)//
.setCacheable(true)// 把查询语句缓存起来,以后使用就是使用缓存了
.uniqueResult();
System.out.println(department);
// --------------------------------------------------------------
tx.commit();
session.close();
System.out.println("/n----------/n");
// ==========================================================
// 第二个Session
session = sessionFactory.openSession();
tx = session.beginTransaction();
// --------------------------------------------------------------
Department department2 = (Department) session.createQuery(//
"FROM Department d WHERE d.id=?")//
.setParameter(0, 1)//
.setCacheable(true)// 使用查询缓存
.uniqueResult();
System.out.println(department2);
// --------------------------------------------------------------
tx.commit();
session.close();
}
如果类中有集合,则集合不会缓存进来,除非设置集合缓存:
<collection-cache usage="read-write" collection="..senondcache.Department.employees"/>
还有另外一种缓存,叫时间戳缓存.
时间戳缓存就是指定Hibernate的二级缓存会自动的检测,如果使用了Update或Delete语句,则把一些数据清出缓存,但是它只会清出二级缓存,如果要更新一级缓存,必须使用refresh()方法.
最后还有一个和缓存相关的,使用Query对象.
Query.list()不会使用缓存,除非调用了.setCacheable(true)才可以,但是HQL一变或参数变了,就不会再用缓存的结果了.
但是Query.iterate()会使用类缓存,原理是:
@Test
public void testQueryIterate() {
// ==========================================================
// 第一个Session
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// --------------------------------------------------------------
List list = session.createQuery("FROM Department d WHERE d.id<=2").list();
for(Object obj : list){
System.out.println(obj);
}
// --------------------------------------------------------------
tx.commit();
session.close();
System.out.println("/n----------/n");
// ==========================================================
// 第二个Session
session = sessionFactory.openSession();
tx = session.beginTransaction();
// --------------------------------------------------------------
Iterator iter = session.createQuery("FROM Department d WHERE d.id<=3").iterate();
while(iter.hasNext()){
System.out.println(iter.next());
}
// --------------------------------------------------------------
tx.commit();
session.close();
}