Hibernate:缓存设置

本文详细介绍了缓存的作用及其在应用程序中的重要性。缓存位于应用程序与物理数据源之间,旨在减少直接访问物理数据源的需求,从而提升应用性能。文章还深入探讨了Hibernate中的一级缓存和二级缓存的具体实现细节及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[color=red] 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。

  缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。[/color]


hibernate 一级缓存:(缓存的是实体对象)

一级缓存很短和session的生命周期一致,一级缓存也叫session级的缓存或事务缓存



哪些方法支持一级缓存:

*get()

*load()

*iterate() (查询实体对象)



如何管理一级缓存:

* session.clear() session.evict()



如何避免一次性大量的实体数据入库导致内存溢出

*先flush,再clear



如果数据量特别大,考虑采用jdbc实现,如果jdbc也不能满足要求,可以考虑采用数据库本身的特定导入工具



一.Load测试: 在同一个session中发出两次load查询

       Student sutdent = (Student)session.load(Student.class,1);

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



sutdent = (Student)session.load(Student.class,1);

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


在同一个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候也不会查询数据库,因为他在缓存里找到,不会发出sql





Load测试: 开启两个session中发出两次load查询

Student sutdent = (Student)session.load(Student.class,1);

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

sessioin.close();

………..

sutdent = (Student)session.load(Student.class,1);

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


开启两个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候查询数据库,因为session间不能共享一级缓存的数据,因为他会随session的生命周期存在和消亡





二.Get测试: 在同一个session中发出两次get查询

  Student sutdent = (Student)session.get(Student.class,1);

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



sutdent = (Student)session.get(Student.class,1);

System.out.println(student.getName());
在同一个session中发出两次get查询, 第一次get的时候去查询数据库,第二次get的时候不会查询数据库,因为他在缓存里找到,不会发出sql





三.iterate测试: 在同一个session中发出两次iterator查询

Student student = (Student)session.createQuery(“from Student s where s.id=1”).iterate().next();

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



student = (Student)session.createQuery(“from Student s where s.id=1”).iterate().next();

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

在同一个session中发出两次iterator查询,第一次iterate().next()的时候会发出查询id的sql,使用的时候会发出相应的查询实体对象,第二次iterate().next()的时候会发出查询id的sql,不会发出查询实体对象的sql,因为iterate使用缓存,不会发出sql





四.Iterate查询属性测试: 同一个session中发出两次查询属性

String name = (String)session.createQuery(“select s.name from Student s where s.id=1”).iterate().next();

System.out.println(name);



String name = (String)session.createQuery(“select s.name from Student s where s.id=1”).iterate().next();

System.out.println(name);

在同一个session中发出两次查询属性, 第一次iterate().next()的时候会发出查询属性的sql,第二次iterate().next()的时候会发出查询属性的sql,iterate查询普通属性,一级缓存不会缓存,所以会发出sql





五.同一个session中先save,再发出load查询save过的数据


 Student stu = new Student();

stu.setName(“王五”);



Serializable id = session.save(stu);



Student sutdent = (Student)session.load(Student.class,id);

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




save的时候,他会在缓存里放一份,不会发出sql,因为save是使用缓存的

六.同一个session中先调用load查询,然后执行sessio.clear()或session.evict(),再调用load查询



Student sutdent = (Student)session.load(Student.class,1);

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

session.clear();



Student sutdent = (Student)session.load(Student.class,1);

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




sessio.clear()或session.evict()可以管理一级缓存,一级缓存无法取消,但可以管理.

上面的语句都会发出sql 因为一级缓存中的实体被清除了



七.向数据库中批量加入1000条数据



for(int i=0;i<1000;i++){

Student student = new Student();

student.setName(“s” + i);

session.save(student);

//每20条数据就强制session将数据持久化,同时清除缓存,避免大量数据造成内存溢出

if( i %20 == 0 ){

session.flush();

session.clear();

}

}

[color=red]=========================================================================================[/color]


hibernate 二级缓存:(缓存的是实体对象,二级缓存是放变化不是很大的数据)

[img]http://www.blogjava.net/images/blogjava_net/lsbwahaha/11111.jpg[/img]
[img]http://www.blogjava.net/images/blogjava_net/lsbwahaha/2222.jpg[/img]

二级缓存也称进程级的缓存或SessionFactory级的缓存,而二级缓存可以被所有的session(hibernate中的)共享二级缓存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二级缓存



二级缓存的配置和使用:

1.将echcache.xml文件拷贝到src下, 二级缓存hibernate默认是开启的,手动开启

2.开启二级缓存,修改hibernate.cfg.xml文件,

<property name=”hibernate.cache.user_second_level_cache”>true</property>

3.指定缓存产品提供商

<property name=”hibernate.cache.provider_calss”>org.hibernate.cache.EhCacheProvider</property>



4.指定那些实体类使用二级缓存(两种方法,推荐使用第二种)

第一种:在*.hbm.xml中,在<id>之前加入

<cache usage=”read-only” />, 使用二级缓存

第二种:在hibernate.cfg.xml配置文件中,在<mapping resource=”com/Studnet.hbm.xml” />后面加上:

<class-cache class=” com.Studnet” usage=”read-only” />



二级缓存是缓存实体对象的

了解一级缓存和二级缓存的交互









测试二级缓存:

一.开启两个session中发出两次load查询(get与load一样,同样不会查询数据库),

Student sutdent = (Student)session.load(Student.class,1);

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

sessioin.close();

………..

sutdent = (Student)session.load(Student.class,1);

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

开启两个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候查询数据库,开启了二级缓存,也不会查询数据库。





二.开启两个session,分别调用load,再使用sessionFactory清楚二级缓存

Student sutdent = (Student)session.load(Student.class,1);

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

sessioin.close();

………..

SessionFactory factory = HibernateUtil.getSessionFactory();

//factory.evict(Student.class); //清除所有Student对象

Factory.evict(Student.class,1); //清除指定id=1 的对象



sutdent = (Student)session.load(Student.class,1);

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

开启两个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候查询数据库,它要查询数据库,因为二级缓存中被清除了



三.一级缓存和二级缓存的交互



session.setCacheMode(CacheMode.GET); //设置成 只是从二级缓存里读,不向二级缓存里写数据

Student sutdent = (Student)session.load(Student.class,1);

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

sessioin.close();

………..

SessionFactory factory = HibernateUtil.getSessionFactory();

//factory.evict(Student.class); //清除所有Student对象

Factory.evict(Student.class,1); //清除指定id=1 的对象



sutdent = (Student)session.load(Student.class,1);

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

开启两个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候查询数据库,它要查询数据库,因为 设置了CacheMode为GET,(load设置成不能往二级缓冲中写数据), 所以二级缓冲中没有数据







session.setCacheMode(CacheMode.PUT); //设置成只是向二级缓存里写数据,不读数据

Student sutdent = (Student)session.load(Student.class,1);

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

sessioin.close();

………..

SessionFactory factory = HibernateUtil.getSessionFactory();

//factory.evict(Student.class); //清除所有Student对象

Factory.evict(Student.class,1); //清除指定id=1 的对象



sutdent = (Student)session.load(Student.class,1);

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

开启两个session中发出两次load查询,第一次load的时候不会去查询数据库,因为他是LAZY的,当使用的时候才去查询数据库, 第二次load的时候也不会,当使用的时候查询数据库,它要查询数据库,因为设置了CacheMode为POST,(load设置成只是向二级缓存里写数据,不读数据)

====================================================================================



hibernate查询缓存(hibernate默认是关闭的)



查询缓存是针对普通属性结果集的缓存

对实体对象的结果集只缓存id



查询缓存的生命周期,当前关联的表发生修改,那么查询缓存生命周期结束



查询缓存的配置和使用:

1. 启用查询缓存:在hibernate.cfg.xml中加入:

<property name=”hibernate.cache.use_query_cache”>true</property>

2. 在程序中必须手动启用查询缓存,如:query.setCacheable(true);





测试查询缓存:

一. 开启查询缓存,关闭二级缓存,开启一个session,分别调用query.list (查询属性)



Query query = session.createQuery(“select s.name from Student s”);

//启用查询缓存

query.setCacheable(true);



List names = query.list();

for(Iterator iter = names.terator();iter.hasNext();){

String name = (String)iter.next();

System.out.println(name);

}



System.out.println(“------------------------------------------”);



query = session.createQuery(“select s.name from Student s”);

//启用查询缓存

query.setCacheable(true);



names = query.list();

for(Iterator iter = names.terator();iter.hasNext();){

String name = (String)iter.next();

System.out.println(name);

}

第二次没有去查询数据库,因为启用了查询缓存



二. 开启查询缓存,关闭二级缓存,开启两个session,分别调用query.list (查询属性)



Query query = session.createQuery(“select s.name from Student s”);

//启用查询缓存

query.setCacheable(true);



List names = query.list();

for(Iterator iter = names.terator();iter.hasNext();){

String name = (String)iter.next();

System.out.println(name);

}



session.close();



System.out.println(“------------------------------------------”);

………

Query query = session.createQuery(“select s.name from Student s”);

//启用查询缓存

query.setCacheable(true);



List names = query.list();

for(Iterator iter = names.terator();iter.hasNext();){

String name = (String)iter.next();

System.out.println(name);

}

第二次没有去查询数据库,因为查询缓存生命周期与session生命周期无关



三. 开启查询缓存,关闭二级缓存,开启两个session,分别调用query.iterate (查询属性)



Query query = session.createQuery(“select s.name from Student s”);

//启用查询缓存

query.setCacheable(true);



for(Iterator iter =query.iterate();iter.hasNext();){

String name = (String)iter.next();

System.out.println(name);

}



session.close();



System.out.println(“------------------------------------------”);

………

Query query = session.createQuery(“select s.name from Student s”);

//启用查询缓存

query.setCacheable(true);



for(Iterator iter = query.iterate();iter.hasNext();){

String name = (String)iter.next();

System.out.println(name);

}

第二去查询数据库,因为查询缓存只对query.list()起作用,对query.iterate()不起作用,也就是说query.iterate()不使用查询缓存



四. 关闭查询缓存,关闭二级缓存,开启两个session,分别调用query.list (查询实体对象)



Query query = session.createQuery(“ from Student s”);

//query.setCacheable(true);

List students = query.list();

for(Iterator iter = students.iterate();iter.hasNext();){

Student stu = (Student)iter.next();

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

}



session.close();



System.out.println(“------------------------------------------”);

………

Query query = session.createQuery(“ from Student s”);

//query.setCacheable(true);

List students = query.list();

for(Iterator iter = students.iterate();iter.hasNext();){

Student stu = (Student)iter.next();

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

}

第二去查询数据库,因为list默认每次都会发出查询sql



五. 开启查询缓存,关闭二级缓存,开启两个session,分别调用query.list (查询实体对象)



Query query = session.createQuery(“ from Student s”);

query.setCacheable(true);

List students = query.list();

for(Iterator iter = students.iterate();iter.hasNext();){

Student stu = (Student)iter.next();

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

}



session.close();



System.out.println(“------------------------------------------”);

………

Query query = session.createQuery(“ from Student s”);

query.setCacheable(true);

List students = query.list();

for(Iterator iter = students.iterate();iter.hasNext();){

Student stu = (Student)iter.next();

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

}

第二去查询数据库时,会发出N条sql语句,因为开启了查询缓存,关闭了二级缓存,那么查询缓存会缓存实体对象的id,所以hibernate会根据实体对象的id去查询相应的实体,如果缓存中不存在相应的实体,那么将发出根据实体id查询的sql语句,否则不会发出sql,使用缓存中的数据



六. 开启查询缓存,开启二级缓存,开启两个session,分别调用query.list (查询实体对象)



Query query = session.createQuery(“ from Student s”);

query.setCacheable(true);

List students = query.list();

for(Iterator iter = students.iterate();iter.hasNext();){

Student stu = (Student)iter.next();

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

}



session.close();



System.out.println(“------------------------------------------”);

………

Query query = session.createQuery(“ from Student s”);

query.setCacheable(true);

List students = query.list();

for(Iterator iter = students.iterate();iter.hasNext();){

Student stu = (Student)iter.next();

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

}



第二不会发出sql,因为开启了二级缓存和查询缓存,查询缓存缓存了实体对象的id列表,hibernate会根据实体对象的id列表到二级缓存中取得相应的数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值