java中的接口是类吗
179
2023-06-15
Hibernate缓存详解
1. 什么是缓存?
数据库的缓存指的是应用程序和物理数据源之间的数据。即把物理数据源的数据复制到缓存。有了缓存,可以降低应用程序对物理数据源的访问频率,从而提高效率。缓存的介质一般是内存,也可以是硬盘。
Hibernate的缓存有三种类型:一级缓存、二级缓存和查询缓存。
2. 一级缓存
一级缓存即Session缓存,由Session自动进行管理,不需要程序进行干预。一级缓存根据对象的ID进行加载和缓存。如下面的代码:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Course c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
}
运行结果:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:计算机原理
Name:计算机原理
第1次查询时生成了SQL语句,并将查询出来的对象放在一级缓存里面,第2次查询时,在一级缓存里面直接找到了这个对象,就不需要再次生成SQL语句了。
再看一个例子:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Course c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
}
由于一级缓存是Session级别的缓存,所以Session关闭以后,一级缓存也就不存在了,第2次查询也要生成SQL语句:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:计算机原理
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:计算机原理
3. 二级缓存
二级缓存即SessionFactory缓存,和一级缓存类似,也是根据对象的ID进行加载和缓存,区别就在于一级缓存只在Session内有效,而二级缓存在SessionFactory内有效。在访问某个ID的对象时,先到一级缓存里面去找,如果没有找到就到二级缓存里面去找。二级缓存包括EHCache,OSCache,SwarmCache和JBossCache等。这里以EHCache作为例子。
二级缓存需要程序进行管理。首先,配置Maven下载相关的Jar,在pom文件里面添加:
创建EHCache配置文件ehcache.xml:
maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> defaultCache是默认的设置,下面一个cache指明了对哪一个类进行二级缓存。里面设置了最大缓存的对象数量,是否永久有效、最大空闲秒数、最大生存秒数、内存满时是否写到硬盘,写到硬盘的路径等等。 修改需要缓存的类的hbm文件: ...... usage设置了并发访问策略,一般设置成read-only。 修改applicationContext.xml中的SessionFactory的配置,增加二级缓存的一些属性: ...... 运行下面的例子: @OverkmzYhride public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); session = sessionFactory.openSession(); tx = session.beginTransaction(); c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); } 结果: Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Name:计算机原理 Name:计算机原理 虽然关闭了Session,但是二级缓存仍然存在,所以只生成了一次SQL语句。 下面的例子: @Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("from Course"); Iterator iter = query.iterate(); while(iter.hasNext()){ System.out.println(((Course)iter.next()).getName()); } tx.commit(); session.close(); session = sessionFactory.openSession(); tx = session.beginTransaction(); query = session.createQuery("from Course"); iter = query.iterate(); while(iter.hasNext()){ System.out.println(((Course)iter.next()).getName()); } tx.commit(); session.close(); } 结果: Hibernate: select course0_.ID as col_0_0_ from clas course0_ Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 计算机原理 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 计算机网络 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 数据库原理 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? C语言 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 大学英语A Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? java Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? linux Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 高等数学 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 语文 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 大学物理 Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 软件工程 Hibernate: select course0_.ID as col_0_0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 当使用Query的list()方法时,只生成一次SQL语句查询出所有的对象,使用iterate()方法时,会先得到所有对象的ID,然后根据每个ID生成一次SQL语句查询。第二个Session里面使用的也是iterate()方法,首先生成一次SQL语句,得到ID,然后根据ID查找对象,由于开启了二级缓存,在二级缓存里面找到了对象,所以就直接输出了,并没有再根据每个ID生成SQL语句。 不论是一级缓存还是二级缓存,都只能缓存对象,不能缓存属性的值。下面的例子: @Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.name from Course c"); List for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); query = session.createQuery("select c.name from Course c"); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); tx.commit(); session.close(); } 运行结果: Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 虽然开启了二级缓存,但是查询的结果不是对象,是属性,所以并没有缓存,第2次查询仍然生成了查询语句。要解决这个问题,就需要查询缓存。 3. 查询缓存 在配置了二级缓存的基础上,可以设置查询缓存,在SessionFactory的设置里面加上一行: 即打开了查询缓存。查询缓存也是SessionFactory级别的缓存,在整个SessionFactory里面都是有效的。 关闭二级缓存,运行下面的例子,在Query后面添加setCacheable(true)打开查询缓存: @Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.name from Course c"); query.setCacheable(true); List for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); query = session.createQuery("select c.name from Course c"); query.setCacheable(true); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); tx.commit(); session.close(); } 结果: Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 由于两次查询的HQL语句是一致的,所以只生成一次SQL语句。但是如果把第二次查询改一下: System.out.println("----------"); query = session.createQuery("select c.name from Course c where c.id > 5"); query.setCacheable(true); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); 结果: Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- Hibernate: select course0_.NAME as col_0_0_ from clas course0_ where course0_.ID>5 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 由于HQL语句变了,所以第二次也生成了SQL语句。 查询缓存可以缓存属性,也可以缓存对象,但是当缓存对象时,只缓存对象的ID,不会缓存整个对象。下面的例子: @Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("from Course"); query.setCacheable(true); List for (int i=0; i System.out.println(list.get(i).getName()); } System.out.println("----------"); tx.commit(); session.close(); session = sessionFahttp://ctory.openSession(); tx = session.beginTransaction(); query = session.createQuery("from Course"); query.setCacheable(true); list = query.list(); for (int i=0; i System.out.println(list.get(i).getName()); } System.out.println("----------"); tx.commit(); session.close(); } 结果: Hibernate: select course0_.ID as ID0_, course0_.NAME as NAME0_, course0_.COMMENT as COMMENT0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 由于开了查询缓存,没有开二级缓存,虽然使用的是list()方法一次查询出了所有的对象,但是查询缓存只缓存了对象ID,没有缓存整个对象。所以在第2个Session里面"from Course"这个HQL由于和前面的相同,并没有生成SQL语句,但是由于没有开二级缓存,没有缓存整个对象,只能根据每个ID去生成一次SQL语句。虽然两次用的都是list()方法,但是第一次是生成SQL语句去一次查询出所有的对象,而第二次是根据查询缓存里面的ID一个一个的生成SQL语句。 如果同时打开查询缓存和二级缓存,第2个Session里面就不用再根据ID去生成SQL语句了: Hibernate: select course0_.ID as ID0_, course0_.NAME as NAME0_, course0_.COMMENT as COMMENT0_ from clas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ----------
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~