hibernate 一級緩存:(緩存的是實體對象)
一級緩存很短和session的生命周期一致,一級緩存也叫session級的緩存或事務緩存
哪些方法支持一級緩存:
*get()
*load()
*iterate() (查詢實體對象)
如何管理一級緩存:
* session.clear() session.evict()
如何避免一次性大量的實體數(shù)據(jù)入庫導致內存溢出
*先flush,再clear
如果數(shù)據(jù)量特別大,考慮采用jdbc實現(xiàn),如果jdbc也不能滿足要求,可以考慮采用數(shù)據(jù)庫本身的特定導入工具
一.Load測試: 在同一個session中發(fā)出兩次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中發(fā)出兩次load查詢,第一次load的時候不會去查詢數(shù)據(jù)庫,因為他是LAZY的,當使用的時候才去查詢數(shù)據(jù)庫, 第二次load的時候也不會,當使用的時候也不會查詢數(shù)據(jù)庫,因為他在緩存里找到,不會發(fā)出sql
Load測試: 開啟兩個session中發(fā)出兩次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中發(fā)出兩次load查詢,第一次load的時候不會去查詢數(shù)據(jù)庫,因為他是LAZY的,當使用的時候才去查詢數(shù)據(jù)庫, 第二次load的時候也不會,當使用的時候查詢數(shù)據(jù)庫,因為session間不能共享一級緩存的數(shù)據(jù),因為他會隨session的生命周期存在和消亡
二.Get測試: 在同一個session中發(fā)出兩次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中發(fā)出兩次get查詢, 第一次get的時候去查詢數(shù)據(jù)庫,第二次get的時候不會查詢數(shù)據(jù)庫,因為他在緩存里找到,不會發(fā)出sql
三.iterate測試: 在同一個session中發(fā)出兩次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中發(fā)出兩次iterator查詢,第一次iterate().next()的時候會發(fā)出查詢id的sql,使用的時候會發(fā)出相應的查詢實體對象,第二次iterate().next()的時候會發(fā)出查詢id的sql,不會發(fā)出查詢實體對象的sql,因為iterate使用緩存,不會發(fā)出sql
四.Iterate查詢屬性測試: 同一個session中發(fā)出兩次查詢屬性
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中發(fā)出兩次查詢屬性, 第一次iterate().next()的時候會發(fā)出查詢屬性的sql,第二次iterate().next()的時候會發(fā)出查詢屬性的sql,iterate查詢普通屬性,一級緩存不會緩存,所以會發(fā)出sql
五.同一個session中先save,再發(fā)出load查詢save過的數(shù)據(jù)
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的時候,他會在緩存里放一份,不會發(fā)出sql,因為save是使用緩存的
六.同一個session中先調用load查詢,然后執(zhí)行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()可以管理一級緩存,一級緩存無法取消,但可以管理.
上面的語句都會發(fā)出sql 因為一級緩存中的實體被清除了
七.向數(shù)據(jù)庫中批量加入1000條數(shù)據(jù)
for(int i=0;i<1000;i++){
Student student = new Student();
student.setName(“s” + i);
session.save(student);
//每20條數(shù)據(jù)就強制session將數(shù)據(jù)持久化,同時清除緩存,避免大量數(shù)據(jù)造成內存溢出
if( i %20 == 0 ){
session.flush();
session.clear();
}
}
=========================================================================================
hibernate 二級緩存:(緩存的是實體對象,二級緩存是放變化不是很大的數(shù)據(jù))


二級緩存也稱進程級的緩存或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中發(fā)出兩次load查詢(get與load一樣,同樣不會查詢數(shù)據(jù)庫),
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中發(fā)出兩次load查詢,第一次load的時候不會去查詢數(shù)據(jù)庫,因為他是LAZY的,當使用的時候才去查詢數(shù)據(jù)庫, 第二次load的時候也不會,當使用的時候查詢數(shù)據(jù)庫,開啟了二級緩存,也不會查詢數(shù)據(jù)庫。
二.開啟兩個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中發(fā)出兩次load查詢,第一次load的時候不會去查詢數(shù)據(jù)庫,因為他是LAZY的,當使用的時候才去查詢數(shù)據(jù)庫, 第二次load的時候也不會,當使用的時候查詢數(shù)據(jù)庫,它要查詢數(shù)據(jù)庫,因為二級緩存中被清除了
三.一級緩存和二級緩存的交互
session.setCacheMode(CacheMode.GET); //設置成 只是從二級緩存里讀,不向二級緩存里寫數(shù)據(jù)
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中發(fā)出兩次load查詢,第一次load的時候不會去查詢數(shù)據(jù)庫,因為他是LAZY的,當使用的時候才去查詢數(shù)據(jù)庫, 第二次load的時候也不會,當使用的時候查詢數(shù)據(jù)庫,它要查詢數(shù)據(jù)庫,因為 設置了CacheMode為GET,(load設置成不能往二級緩沖中寫數(shù)據(jù)), 所以二級緩沖中沒有數(shù)據(jù)
session.setCacheMode(CacheMode.PUT); //設置成只是向二級緩存里寫數(shù)據(jù),不讀數(shù)據(jù)
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中發(fā)出兩次load查詢,第一次load的時候不會去查詢數(shù)據(jù)庫,因為他是LAZY的,當使用的時候才去查詢數(shù)據(jù)庫, 第二次load的時候也不會,當使用的時候查詢數(shù)據(jù)庫,它要查詢數(shù)據(jù)庫,因為設置了CacheMode為POST,(load設置成只是向二級緩存里寫數(shù)據(jù),不讀數(shù)據(jù))
====================================================================================
hibernate查詢緩存(hibernate默認是關閉的)
查詢緩存是針對普通屬性結果集的緩存
對實體對象的結果集只緩存id
查詢緩存的生命周期,當前關聯(lián)的表發(fā)生修改,那么查詢緩存生命周期結束
查詢緩存的配置和使用:
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);
}
第二次沒有去查詢數(shù)據(jù)庫,因為啟用了查詢緩存
二. 開啟查詢緩存,關閉二級緩存,開啟兩個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);
}
第二次沒有去查詢數(shù)據(jù)庫,因為查詢緩存生命周期與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);
}
第二去查詢數(shù)據(jù)庫,因為查詢緩存只對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());
}
第二去查詢數(shù)據(jù)庫,因為list默認每次都會發(fā)出查詢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());
}
第二去查詢數(shù)據(jù)庫時,會發(fā)出N條sql語句,因為開啟了查詢緩存,關閉了二級緩存,那么查詢緩存會緩存實體對象的id,所以hibernate會根據(jù)實體對象的id去查詢相應的實體,如果緩存中不存在相應的實體,那么將發(fā)出根據(jù)實體id查詢的sql語句,否則不會發(fā)出sql,使用緩存中的數(shù)據(jù)
六. 開啟查詢緩存,開啟二級緩存,開啟兩個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());
}
第二不會發(fā)出sql,因為開啟了二級緩存和查詢緩存,查詢緩存緩存了實體對象的id列表,hibernate會根據(jù)實體對象的id列表到二級緩存中取得相應的數(shù)據(jù)
柳德才
13691193654
18942949207
QQ:422157370
liudecai_zan@126.com湖北-武漢-江夏-廟山