1、什么是缓存
什么是缓存:并不是指计算机的内存或者CPU的一二级缓存。
缓存是指为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能的一种策略。
为什么使用缓存:ORM框架访问数据库的效率直接影响应用程序的运行速度,提升和优化ORM框架的执行效率至 关重要。
Hibernate 的缓存是提升和优化Hibernate执行效率的重要手段,所以学会Hibernate缓存的使 用和配置是优化的关键
缓存的一般工作原理
当下一次要获取数据时就不用在数据源中去获取而是直接在缓存中获取,而缓存是存储在应用程序的内存中,这样会极大的提高获取数据的效率
工作原理
2、Hibernate一级缓存
看如下代码
@Test
public void testGetUser()
{
User user= (User)session.get(User.class, 1);
System.out.println(user);
user=(User)session.get(User.class, 1);
System.out.println(user);
}
运行显示如下
发现sql语句只发送了一次,第二次查询同一个对象时,并没有再次执行数据库查询,这是因为它使用了Hibernate的缓存
对代码做如下修改
@Test
public void getStudent()
{
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Student s = (Student)session.get(Student.class, 1);
System.out.println(s.getSname());
//使用不同的session进行第二次查询
session = sessionFactory.openSession();
s=(Student)session.get(Student.class, 1);
System.out.println(s.getSname());
HibernateUtil.closeSession(session);
}
发现sql语句发送了俩遍,因此可以得出如下结论,在不同的session中多次查询同一对象时,会执行多次数据库查询
在一级缓存中,持久化类的每个实例都具有唯一的OID。
介绍Hibernate一级缓存
1、Hibernate一级缓存又称为“Session缓存”、“会话级缓存”
2、通过Session从数据库查询实体时会把实体在内存中存储起来,下一次查询同一实体时不再从数据库获取,从 而内存中获取,这就是缓存
3、一级缓存的生命周期和Session相同;Session销毁,它也销毁。
4、一级缓存中的数据可适用范围在当前会话之内。
Hibernate一级缓存的API
一级缓存无法取消(Hibernate默认强制使用一级缓存),用俩个方法管理
evict():用于将某个对象从Session的一级缓存中清除
clear():用于将一级缓存中的所有对象全部清除。
一级缓存也有些时候会对程序的性能产生影响。这是因为在进行增删改查时也要对一级缓存进行更新。因此一级缓存只能提高查询效率。
将代码进行如下修改
@Test
public void getStudent()
{
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
/* Student s = (Student)session.get(Student.class, 1);
System.out.println(s.getSname());
//evict方法清除一级缓存中的指定对象
//session.evict(s);
//clear清除一级缓存中的所有内容
session.clear();
//使用不同的session进行第二次查询
//session = sessionFactory.openSession();
s=(Student)session.get(Student.class, 1);
System.out.println(s.getSname());*/
Query query = session.createQuery("from Student");
List<Student> list=query.list();
for(Student s:list)
{
System.out.println(s.getSname());
}
list=query.list();
for(Student s:list)
{
System.out.println(s.getSname());
}
HibernateUtil.closeSession(session);
}
执行结果
发现query.list并没有一级缓存
将代码做如下修改,发现第二次sql语句只进行了sid查询
@Test
public void getStudent()
{
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
/* Student s = (Student)session.get(Student.class, 1);
System.out.println(s.getSname());
//evict方法清除一级缓存中的指定对象
//session.evict(s);
//clear清除一级缓存中的所有内容
session.clear();
//使用不同的session进行第二次查询
//session = sessionFactory.openSession();
s=(Student)session.get(Student.class, 1);
System.out.println(s.getSname());*/
Query query = session.createQuery("from Student");
List<Student> list=query.list();
for(Student s:list)
{
System.out.println(s.getSname());
}
Iterator it =query.iterate();
while(it.hasNext())
{
Student s=(Student)it.next();
System.out.println(s.getSname());
}
HibernateUtil.closeSession(session);
}
当把list部分代码去除掉发现
@Test
public void getStudent()
{
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
/* Student s = (Student)session.get(Student.class, 1);
System.out.println(s.getSname());
//evict方法清除一级缓存中的指定对象
//session.evict(s);
//clear清除一级缓存中的所有内容
session.clear();
//使用不同的session进行第二次查询
//session = sessionFactory.openSession();
s=(Student)session.get(Student.class, 1);
System.out.println(s.getSname());*/
Query query = session.createQuery("from Student");
/*List<Student> list=query.list();
for(Student s:list)
{
System.out.println(s.getSname());
}*/
Iterator it =query.iterate();
while(it.hasNext())
{
Student s=(Student)it.next();
System.out.println(s.getSname());
}
HibernateUtil.closeSession(session);
}
这是因为query.iterator首先从student表中查询出所有的student编号,然后在缓存中根据student编号查询对应的学生,如果找到对应的student那么直接从缓存中拿到,如果没有则进入数据库拿到相应的student信息,这就是为什么没有去处query.list()时后面的代码不用因为query.list已经将所有的信息放入到了缓存,query.iterator会进行缓存查询。这也是query.list与query.iterator的区别。
3、Hibernate二级缓存
有些常用的数据,在一个session中缓存以后,我们希望在其它session中能够直接使用,而不用再次缓存怎么办?这是我们将使用更高级别的二级缓存,每个session共用的缓存。
二级缓存的配置步骤
① 添加二级缓存对应的jar包
②在Hibernate的配置文件中添加Provider类的描叙。
<property name="cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
注意:在Hibernate4中千万不能如下配置二级缓存否则会报错,错误信息如下
<property name="cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>
③添加二级缓存的属性配置文件
④在需要被缓存的表所对应的映射文件中添加<cache/>标签
再做测试
@Test
public void getSecondSession()
{
SessionFactory sessionFactory =HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Student s = (Student)session.get(Student.class, 1);
System.out.println(s.getSname());
session=sessionFactory.openSession();
s=(Student) session.get(Student.class, 1);
System.out.println(s.getSname());
HibernateUtil.closeSession(session);
}
可见虽然为俩个不同的session但是查询相同数据时只发送了一次sql语句,说明已经应用了二级缓存
<cache/>标签的详细介绍:
usage:指定缓存策略(也就是事务模式),可选策略包括:transactional,read-write,nonstrict-read-write或read-only(常用read-only)
include:指定是否缓存延迟加载的对象,non-lazy 不缓存延时加载的属性对象,all表示缓存所有属性对象
region:可以随意命名表示可以在ehache.xml中对这个表进行特定的缓存策略
一般在ehache.xml中采用的是默认策略即
<!--
maxElementsInMemory="10000"最大缓存数
eternal="false" 缓存是否持久
timeToIdleSeconds="120" 当缓存闲置n秒后销毁
timeToLiveSeconds="120" 当缓存存活n秒后销毁
overflowToDisk="true"是否保存到磁盘,当系统当机时
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
即你的
region属性的名称可对应为你自己定义的缓存策略的名字如你可在ehache.xml中定义自己的缓存策略取名为sampleCache2:
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
二级缓存的介绍
二级缓存又称为“全局缓存”、“应用级缓存”。
并不会随着某个Session的销毁而销毁,
而是随着SessionFactory的销毁而销毁
二级缓存中的数据可适用范围是当前应用的所有会话。
二级缓存是可插拔式缓存,默认是EHCache,还支持其他二级缓存组件如:
Hashtable、OSCache、SwarmCache、JBoss TreeCache等。
在通常情况下会将具有以下特征的数据放入到二级缓存中
①、很少被修改的数据。
②、不是很重要的数据,允许出现偶尔并发的数据。
③、不会被并发访问的数据。
④、参考数据。
4、Hibernate 一二级缓存的对比总结
一二级缓存的对比
总结:
1、Hibernate的缓存能提高检索效率。
2、Hibernate的缓存分为一级缓存和二级缓存。一级缓存是会话级缓存,二级缓存是应用级缓存。
3、Hibernate的缓存在提高检索的同时,也会增加服务器的消耗,所以要注意缓存的使用策略。