Hibernate一级缓存和二级缓存具体解释

时间:2023-03-09 17:02:46
Hibernate一级缓存和二级缓存具体解释

一、一级缓存二级缓存的概念解释

(1)一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中。假设短时间内这个

session(一定要同一个session)又做了同一个操作。那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据;

(2)二级缓存就是SessionFactory级别的缓存,顾名思义。就是查询的时候会把查询结果缓存到二级缓存中,假设同一个sessionFactory

创建的某个session运行了同样的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库;

(3)Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理

的。普通情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓

存能够进行配置和更改,而且能够动态载入和卸载。

Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。

二、一级缓存和二级缓存的比較

(1)第一级缓存 第二级缓存 存放数据的形式相互关联的持久化对象 对象的散装数据 缓存的范围事务范围。每一个事务都有单独的第一级

缓存进程范围或集群范围。缓存被同一个进程或集群范围内的全部事务共享并发訪问策略因为每一个事务都拥有单独的第一级缓存,不

会出现并发问题,无需提供并发訪问策略因为多个事务会同一时候訪问第二级缓存中同样数据。因此必须提供适当的并发訪问策略,来保

证特定的事务隔离级别数据过期策略没有提供数据过期策略。

(2)处于一级缓存中的对象永远不会过期。除非应用程序显式清空缓存或者

清除特定的对象必须提供数据过期策略,如基于内存的缓存中的对象的最大数目,同意对象处于缓存中的最长时间。以及同意对象处

于缓存中的最长空暇时间物理存储介质内存内存和硬盘。

(3)对象的散装数据首先存放在基于内存的缓存中,当内存中对象的数目达到数

据过期策略中指定上限时,就会把其余的对象写入基于硬盘的缓存中。

(4)缓存的软件实如今Hibernate的Session的实现中包括了缓存的

实现由第三方提供,Hibernate仅提供了缓存适配器(CacheProvider)。

用于把特定的缓存插件集成到Hibernate中。

(5)启用缓存的方式

仅仅要应用程序通过Session接口来运行保存、更新、删除、载入和查询数据库数据的操作,Hibernate就会启用第一级缓存。把数据库

中的数据以对象的形式复制到缓存中。对于批量更新和批量删除操作。假设不希望启用第一级缓存,能够绕过Hibernate API。直接

通过JDBC API来运行指操作。

(6)用户能够在单个类或类的单个集合的粒度上配置第二级缓存。

假设类的实例被常常读但非常少被改动,就

能够考虑使用第二级缓存。

(7)仅仅有为某个类或集合配置了第二级缓存,Hibernate在执行时才会把它的实例增加到第二级缓存中。

用户管理缓存的方式第一级缓存的物理介质为内存。因为内存容量有限。必须通过恰当的检索策略和检索方式来限制载入对象的数目。

Session的 evit()方法能够显式清空缓存中特定对象。但这样的方法不值得推荐。第二级缓存的物理介质能够是内存和硬盘。因此第二

级缓存能够存放大量的数据。数据过期策略的maxElementsInMemory属性值能够控制内存中的对象数目。

(8)管理第二级缓存主要包含两个方面:选择须要使用第二级缓存的持久类,设置合适的并发訪问策略:选择缓存适配器,设置合适的数据过期策略。

三、 一级缓存的管理

(1)当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load(),以及调用查询接口的 list()、iterate()或

filter()方法时。假设在Session缓存中还不存在对应的对象。Hibernate就会把该对象增加到第一级缓存中。当清理缓存时,

Hibernate会依据缓存中对象的状态变化来同步更新数据库。

Session为应用程序提供了两个管理缓存的方法: evict(Object obj)

:从缓存中清除參数指定的持久化对象。 clear():清空缓存中全部持久化对象。

(2)save、update、saveOrupdate、load、list、iterate、lock会向一级缓存存放数据。

save 案例:
//加入一个学生
Student student=new Student();
student.setName("小东"); s.save(student);//放入一级缓存 //我立即查询
Student stu2=(Student) s.get(Student.class, student.getId()); //select
System.out.println("你刚刚加入的学生名字是"+stu2.getName());

(3)什么操作会从一级缓存取数据:get、load、list

get / load 会首先从一级缓存中取,如没有.再有不同的操作[get 会马上向数据库发请求。而load 会返回一个代理对象。直到用户真的去使用数据。才会向数据库发请求。

//查询45号学生

			Student stu=(Student) s.get(Student.class, 45);

			System.out.println("|||||||||||||||||||");

			String hql="from Student where id=45";

			Student stu2=(Student) s.createQuery(hql).uniqueResult();

			System.out.println(stu2.getName());

从上面的案例。我们看出 query.list() query.uniueResut() 不会从一级缓取数据! 可是query.list 或者query.uniqueRestu() 会向一级缓存放数据的.

注意:

① 一级缓存不须要配置,就能够使用,它本身没有保护机制,所以我们程序猿要考虑这个问题,我们能够同 evict 或者 clear来清除session缓存中对象. evict 是清除一个对象,clear是清除全部的sesion缓存对象

② session级缓存中对象的生命周期, 当session关闭后。就自己主动销毁.

③ 我们自己用HashMap来模拟一个Session缓存,加深对缓存的深入.

四、Hibernate二级缓存的管理

1. Hibernate二级缓存策略的一般步骤例如以下:

1) 条件查询的时候,总是发出一条select * from table_name where …. (选择全部字段)这种SQL语句查询数据库,一次获得全部的数据对象。

2) 把获得的全部数据对象依据ID放入到第二级缓存中。

3) 当Hibernate依据ID訪问数据对象的时候,首先从Session一级缓存中查;查不到,假设配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果依照ID放入到缓存。

4) 删除、更新、添加数据的时候,同一时候更新缓存。

Hibernate二级缓存策略,是针对于ID查询的缓存策略。对于条件查询则毫无作用。为此。Hibernate提供了针对条件查询的Query Cache。

5) 二级缓存的对象可能放在内存,也可能放在磁盘.

2. 什么样的数据适合存放到第二级缓存中?

1) 非常少被改动的数据

2) 不是非常重要的数据。同意出现偶尔并发的数据

3) 不会被并发訪问的数据

4) 參考数据,指的是供应用參考的常量数据,它的实例数目有限。它的实例会被更多类的实例引用,实例极少或者从来不会被改动。

3. 不适合存放到第二级缓存的数据?

1) 常常被改动的数据

2) 財务数据,绝对不同意出现并发

3) 与其它应用共享的数据。

4. 经常使用的缓存插件 Hibernater二级缓存是一个插件,以下是几种经常使用的缓存插件:

◆EhCache:可作为进程范围的缓存,存放数据的物理介质能够是内存或硬盘。对Hibernate的查询缓存提供了支持。

◆OSCache:可作为进程范围的缓存。存放数据的物理介质能够是内存或硬盘。提供了丰富的缓存数据过期策略。对Hibernate的查询

缓存提供了支持。

◆SwarmCache:可作为群集范围内的缓存。但不支持Hibernate的查询缓存。

◆JBossCache:可作为群集范围内的缓存,支持事务型并发訪问策略,对Hibernate的查询缓存提供了支持。

5. 配置Hibernate二级缓存的主要步骤:

1) 选择须要使用二级缓存的持久化类,设置它的命名缓存的并发訪问策略。

这是最值得认真考虑的步骤。

2) 选择合适的缓存插件,然后编辑该插件的配置文件。

<property name="hbm2ddl.auto">update</property>
<!-- 启动二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 指定使用哪种二级缓存 -->
<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
<mapping resource="com/hsp/domain/Department.hbm.xml" />
<mapping resource="com/hsp/domain/Student.hbm.xml" />
<!-- 指定哪个domain启用二级缓存
特别说明二级缓存策略:
1. read-only
2. read-write
3. nonstrict-read-write
4. transcational
-->
<class-cache class="com.hsp.domain.Student" usage="read-write"/>

3)能够把oscache.properties文件放在 src文件夹下,这样你能够指定放入二级缓存的对象capacity 大小. 默认1000

6.使用二级缓存:

// TODO Auto-generated method stub
//通过获取一个sesion,让hibernate框架执行(config->载入hibernate.cfg.xml)
Session s=null;
Transaction tx=null; try {
//我们使用基础模板来解说.
s=HibernateUtil.openSession();
tx=s.beginTransaction(); //查询45号学生 Student stu1=(Student) s.get(Student.class, 45);//45->一级缓存
System.out.println(stu1.getName()); tx.commit(); } catch (Exception e) {
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}finally{ if(s!=null && s.isOpen()){
s.close();
}
} System.out.println("*********************************");
try {
//我们使用基础模板来解说.
s=HibernateUtil.openSession();
tx=s.beginTransaction(); //查询45号学生 Student stu1=(Student) s.get(Student.class, 45);
System.out.println(stu1.getName()); Student stu3=(Student) s.get(Student.class, 46);
System.out.println(stu3.getName());
tx.commit(); } catch (Exception e) {
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}finally{ if(s!=null && s.isOpen()){
s.close();
}
} //完毕一个统计,统计的信息在Sessfactory
//SessionFactory对象.
Statistics statistics= HibernateUtil.getSessionFactory().getStatistics();
System.out.println(statistics);
System.out.println("放入"+statistics.getSecondLevelCachePutCount());
System.out.println("命中"+statistics.getSecondLevelCacheHitCount());
System.out.println("错过"+statistics.getSecondLevelCacheMissCount());

在配置了二级缓存后。请大家要注意能够通过 Statistics,查看你的配置命中率高不高