一:二级缓存的基本配置:(这里使用EHCache)
1、 第一步:导入ehcache的jar包(3个)
2、第二步:配置ehcache默认的核心配置文件:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<
diskStore
path
=
"java.io.tmpdir"
/>
<
defaultCache
maxElementsInMemory
=
"10000"
eternal
=
"false"
timeToIdleSeconds
=
"120"
timeToLiveSeconds
=
"120"
overflowToDisk
=
"true"
maxElementsOnDisk
=
"10000000"
diskPersistent
=
"false"
diskExpiryThreadIntervalSeconds
=
"120"
memoryStoreEvictionPolicy
=
"LRU"
/>
</
ehcache
>
3、第三步:配置hibernate核心配置文件:启用二级缓存
这一步在hibernate.cfg.xml中配置
<!-- 使用二级缓存 -->
<
property
name
=
"hibernate.cache.use_second_level_cache"
>
true
</
property
>
4、第四步:配置二级缓存提供商(这个可以在hibernate.properties文件中找到相应的语句 )
<!-- 配置二级缓存提供商 -->
<
property
name
=
"hibernate.cache.provider_class"
>
org.hibernate.cache.EhCacheProvider
</
property
>
5、第五步:配置要缓存的目标数据(类)和并发策略(你要缓存哪些数据-对象)
备注:这个配置有两种方式:在hibernate灵魂文件中配置;在hbm.xml文件中配置
但是我们推荐在hibernate灵魂文件中进行配置
<!-- 配置要缓存的目标数据(类)和并发策略 -->
<!-- 备注1:这个配置需要在mapping之后进行配置 -->
<!-- 备注2:局部配置,在需要使用二级缓存的类中,进行配置,但是不推荐使用 -->
<
class-cache
usage
=
"read-write"
class
=
"cn.cqy.a_isolation.Book"
/>
在hbm.xml文件中配置介绍:
注意:局部的配置会覆盖全局的配置
二:关联集合级别的缓存区域存储
特性:关联集合级别的缓存区域只会缓存OID,具体数据会保存类级别缓冲区中
这里的例子:使用Customer和Order
配置:有两种方法,
方法一:在hibernate.cfg.xml中配置集合级别缓存(这是推荐方法)
方法二:在hbm中配置(这种方式不推荐)
三:查询缓存
上面的二级缓存只能通过load/get/query.iterate来获取,query.List是只能存,不能取数据的
1、什么是查询缓存?
答:查询缓存是基本二级缓存的补充,也是二级缓存的一部分,是一种特殊的二级缓存,
主要是用来保存经常查询的sql语句和“结果”(也有人称之为:三级缓存)
2、基本二级缓存和查询缓存的区别(查询条件不同,返回结果不同)
基本二级缓存:查询条件是记录的id,返回整条记录散装数据---可封装为实体对象
查询缓存:查询条件 使用任何sql语句,返回任何 sql执行结果,缓存的结果更加灵活(可解决query.list无法读取二级缓存的缺陷)
3、查询缓存缺陷:每次必须用代码手动激活查询缓存
不光要在hbm.xml中开启查询缓存,还需要在代码中每次手动激活查询缓存
4、使用步骤
(1)查询缓存依赖类缓存区域,在实际开发中,如果已经配置了类缓存,这个步骤不需要再写
扩展:一般情况下,使用查询缓存的时候,我们会同事开启基本的二级缓存策略
(2)开启查询缓存
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
(3)程序中激活使用:必须激活
语句:query.setCacheable(true)
@Test
public
void
testSelectCache(){
/**
* 证明:查询缓存是存在的,是可以缓存数据的
* 查询缓存主要是解决query.list不走二级缓存的缺陷
* 证明思路:
* 1 开启session1,将数据存入查询缓存
* 2 开启session2,调用query.list从查询缓存获取数据,不发sql语句
*
*/
/***********第一次查询**********/
Session session1 = HibernateUtils.openSession();
session1.beginTransaction();
//如果直接list,数据是不会存入查询缓存
List list = session1.createQuery(
"from Customer"
).setCacheable(
true
).list();
System.
out
.println(list);
session1.getTransaction().commit();
session1.close();
/***********第二次查询**********/
Session session2 = HibernateUtils.openSession();
session2.beginTransaction();
//直接从查询缓存获取数据,不会发sql语句
List list2 = session2.createQuery(
"from Customer"
).setCacheable(
true
).list();
System.
out
.println(list2);
session2.getTransaction().commit();
session2.close();
}
(5)作用
二级缓存不能缓存的内容,就可以查询缓存中缓存,查询缓存又是耳机缓存的补充。但是:如果有一级缓存,尽量用一级缓存,有普通二级缓存尽量用普通二级缓存,实在没办法了,再用查询缓存、
(6)实体查询(目标:验证如果是查询结果可封装为实体的,从查询缓存中取出的是散装数据)
@Test
//测试查询缓存对应的散装数据
public
void
testQueryCacheSanZhuang(){
//使用查询缓存
Session session = HibernateUtils.openSession();
session.beginTransaction();
//查询订单,进行缓存
Query query=session.createQuery(
"from Book"
);
//必须手动打开查询缓存:你放入查询缓存的时候需要手动打开
query.setCacheable(
true
);
List<Book> list=query.list();
System.
out
.println(list.get(0).hashCode());
//一级缓存有,二级缓存有,查询缓存有。
session.getTransaction().commit();
session.close();
//------------------------------------
//一级缓存没了,二级缓存还有,查询缓存还有
Session session2 = HibernateUtils.openSession();
session2.beginTransaction();
//使用查询缓存
Query query2=session2.createQuery(
"from Book"
);
//你从查询缓存中取出的时候还要手动打开
query2.setCacheable(
true
);
List<Book> list2=query2.list();
System.
out
.println(list2.get(0).hashCode());
session2.getTransaction().commit();
session2.close();
//------------------------------------
//一级缓存没了,二级缓存还有,查询缓存还有
Session session3 = HibernateUtils.openSession();
session3.beginTransaction();
//使用查询缓存
Query query3=session3.createQuery(
"from Book"
);
//你从查询缓存中取出的时候还要手动打开
query3.setCacheable(
true
);
List<Book> list3=query3.list();
System.
out
.println(list3.get(0).hashCode());
session3.getTransaction().commit();
session3.close();
}
|
(7)投影查询(目标:验证如果是查询结果不可以封装为实体的,从查询缓存中取出的同一个对象)
@Test
//
测试查询缓存
public
void
testQueryCache(){
///
放入
Session session = HibernateUtils.openSession();
session.beginTransaction();
//
将查询结果放入查询缓存
(
一级缓存,基本二级缓存
)
// Query query = session.createQuery("select name from Book");
Query query = session.createQuery(
"select count(b) from Book b"
);
//
手动开启查询缓存
query.setCacheable(
true
);
//
开启查询缓存的大门了,如果查询,则会将语句缓存到查询缓存。
// List list =query.list();
// System.out.println(list.get(0).hashCode());
long
count1 =(Long) query.uniqueResult();
System.
out
.println(count1);
session.getTransaction().commit();
session.close();
//
取出
Session session2 = HibernateUtils.openSession();
session2.beginTransaction();
//query.list
来取二级缓存,普通的二级缓存是不能取到数据(
by id
),
// Query query2 = session2.createQuery("select name from Book");
Query query2 = session2.createQuery(
"select count(b) from Book b"
);
query2.setCacheable(
true
);
开启查询缓存的大门了
,
就可以从查询缓存中查找需要的数据
// List list2 = query2.list();
// System.out.println(list2.get(0).hashCode());
long
count2 =(Long) query2.uniqueResult();
System.
out
.println(count2);
session2.getTransaction().commit();
session2.close();
}
|
四:监测性能
1、为什么要监测性能?
实际应用中,不是说配置了二级缓存就一定会有效果,需要通过某种途径查看缓存的使用率。
Hibernate SessionFactory 提供了一个统计功能(默认是关闭的):
如果这个功能,开启的话,系统在运行的时候,后台还要不断的统计,浪费效率,浪费资源
而且这个功能,正常是在测试的时候,开启功能
getStatistics
() Get the statistics for this session factory |
通过Statistics这个对象,对二级缓存和查询缓存 进行使用监控
采用会话工厂的统计方法SessionFactory.getStatistics(),包含二级缓存的统计
2、监测步骤
(1)在hibernate.cfg.xml开启统计功能
<!-- 开启统计,监控 -->
<
property
name
=
"hibernate.generate_statistics"
>
true
</
property
>
(2)在程序中通过SessionFactory获取监控数据
@Test
//
缓存使用率性能监控
(
前提是开启了性能监视
)
public
void
testStatistics(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
//
通过会话工厂,获取统计对象
Statistics statistics = sessionFactory.getStatistics();
//
初始状态下,命中次数和丢失次数都是
0
System.
out
.println(
"
二级缓存的命中次数
:"
+statistics.getSecondLevelCacheHitCount());
System.
out
.println(
"
二级缓存的丢失次数
:"
+statistics.getSecondLevelCacheMissCount());
Session session1 = sessionFactory.openSession();
//
原理讲解
//
查询前
2
条订单信息,放入二级缓存
session1.createQuery(
"from Book where id<=2"
).list();
session1.close();
System.
out
.println(
"-
换一个
session-------------------------"
);
Session session2 = sessionFactory.openSession();
//
查询
1
号订单
Book book1 = (Book) session2.get(Book.
class
, 1);
System.
out
.println(book1);
Book book2 = (Book) session2.get(Book.
class
, 2);
System.
out
.println(book2);
System.
out
.println(
"
二级缓存的命中次数
:"
+statistics.getSecondLevelCacheHitCount());
System.
out
.println(
"
二级缓存的丢失次数
:"
+statistics.getSecondLevelCacheMissCount());
System.
out
.println(
"-------------------------"
);
//
查询
1
号订单
Book book4 = (Book) session2.get(Book.
class
, 3);
System.
out
.println(book4);
System.
out
.println(
"
二级缓存的命中次数
:"
+statistics.getSecondLevelCacheHitCount());
System.
out
.println(
"
二级缓存的丢失次数
:"
+statistics.getSecondLevelCacheMissCount());
session2.close();
}
|
提示:平时系统正常运行的时候,不要开这个功能,消耗性能