Hibernate查詢緩存
我們介紹了[Hibernate](http://blog.csdn.net/lovesummerforever/article/details/20997879)[一級緩存](http://blog.csdn.net/lovesummerforever/article/details/20997879),[二級緩存](http://blog.csdn.net/lovesummerforever/article/details/21158769)。而hibernate二級緩存時針對Id查詢的緩存策略,對于條件查詢則毫無作用。因此hibernate提供了針對條件查詢的QueryCache(查詢策略)。
下面來看session控制的查詢緩存。
### 一、查詢緩存配置
1、在hibernate.cfg.xml中加入查詢緩存的策略,<propertyname="hibernate.cache.use_query_cache">true</property>?????啟用查詢緩存的策略,默認是false。
### 二、關閉二級緩存,采用query.list()查詢普通屬性
代碼如下所示。
~~~
public voidtestCache1() {
Session session = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Listnames = session.createQuery("select s.name from Student s")
.setCacheable(true)
.list();
for (int i=0;i<names.size(); i++) {
Stringname = (String)names.get(i);
System.out.println(name);
}
System.out.println("-------------------------------------------------------");
//不會發出查詢語句,因為啟用查詢緩存
names= session.createQuery("select s.name from Student s")
.setCacheable(true)
.list();
for (int i=0;i<names.size(); i++) {
Stringname = (String)names.get(i);
System.out.println(name);
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
我們可以看到控制臺輸出語句,僅輸出一次:Hibernate: select student0_.name as col_0_0_ fromt_student student0_
由此可知,我們開啟了查詢緩存,第一次進行查詢的時候,已經把結果放到querycache中,當第二次再次做出相同的查詢的時候,就不再向數據庫發重復的sql語句了。
### 三、關閉二級緩存,啟用查詢緩存,采用query.list()查詢普通屬性
代碼就如下所示。
~~~
public voidtestCache2() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Listnames = session.createQuery("select s.name from Student s")
.setCacheable(true)
.list();
for (int i=0;i<names.size(); i++) {
Stringname = (String)names.get(i);
System.out.println(name);
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
System.out.println("-------------------------------------------------------");
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//不會發出查詢語句,因為查詢緩存和session的生命周期沒有關系
Listnames = session.createQuery("select s.name from Student s")
.setCacheable(true)
.list();
for (int i=0;i<names.size(); i++) {
Stringname = (String)names.get(i);
System.out.println(name);
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
運行結果如下所示。
控制臺打印結果:
select student0_.name as col_0_0_ fromt_student student0_
班級0的學生0
班級0的學生1
班級0的學生2
班級0的學生3
班級0的學生4
班級0的學生5…
我們可以看出,同樣,只打印一次查詢語句,如果沒有開啟查詢緩存的話,并且關閉二級緩存的情況下,還會去數據庫再查詢一遍,而我們的程序中沒有再去重復的去數據庫中查詢的原因是,當開啟query緩存的時候,查詢緩存的生命周期與session無關。
### 四、關閉二級緩存,開啟查詢,采用query.iterate()查詢普通屬性
代碼如下所示。
~~~
public voidtestCache3() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Iteratoriter = session.createQuery("select s.name from Student s")
.setCacheable(true)
.iterate();
while(iter.hasNext()){
Stringname = (String)iter.next();
System.out.println(name);
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
System.out.println("-------------------------------------------------------");
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//會發出查詢語句,query.iterate()查詢普通屬性它不會使用查詢緩存
//查詢緩存只對query.list()起作用
Iteratoriter = session.createQuery("select s.name from Student s")
.setCacheable(true)
.iterate();
while(iter.hasNext()){
Stringname = (String)iter.next();
System.out.println(name);
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
顯控制臺顯示結果打印了兩次sql語句。
-------------------------------------------------------
Hibernate: select student0_.name as col_0_0_from t_student student0_
根據這樣的結果我們發現,quer.iterate()查詢普通屬性它是不會使用查詢緩存,查詢緩存只對query.list()起作用。
### 五、關閉二級緩存,關閉查詢緩存,采用query.list()查詢實體
代碼如下所示。
~~~
public voidtestCache4() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
List students =session.createQuery("select s from Student s")
.list();
for (int i=0;i<students.size(); i++) {
Studentstudnet = (Student)students.get(i);
System.out.println(studnet.getName());
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
System.out.println("-------------------------------------------------------");
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//會發出查詢語句,默認query.list()每次執行都會發出查詢語句
List students =session.createQuery("select s from Student s")
.list();
for (int i=0;i<students.size(); i++) {
Studentstudnet = (Student)students.get(i);
System.out.println(studnet.getName());
}
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
?顯示結果如下所示。
控制臺上打印兩次sql語句。
Hibernate:select student0_.id as id0_, student0_.name as name0_, student0_.classesid asclassesid0_ from t_student student0_
班級0的學生0
班級0的學生1
班級0的學生2
班級0的學生3
班級0的學生4
由此可知,不開啟查詢緩存,默認query.list每次執行都會發出查詢語句。
### 六、關閉二級緩存,開啟查詢緩存,采用query.list()查詢實體
代碼如下所示。
~~~
Session session = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Liststudents = session.createQuery("select s from Student s")
.setCacheable(true)
.list();
for (int i=0;i<students.size(); i++) {
Studentstudnet = (Student)students.get(i);
System.out.println(studnet.getName());
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
System.out.println("-------------------------------------------------------");
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//會發出n條查詢語句,因為開啟了查詢緩存,關閉了二級緩存,那么查詢緩存就會緩存實體對象的id
//第二次執行query.list(),將查詢緩存中的id依次取出,分別到一級緩存和二級緩存中查詢相應的實體
//對象,如果存在就使用緩存中的實體對象,否則根據id發出查詢學生的語句
Liststudents = session.createQuery("select s from Student s")
.setCacheable(true)
.list();
for (int i=0;i<students.size(); i++) {
Studentstudnet = (Student)students.get(i);
System.out.println(studnet.getName());
}
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
~~~
控制臺打印sql如下圖所示。

在第一次查詢的時候,發出一條sql語句查詢出結果,因為我們開啟了查詢緩存,會把第一次查詢出的實體結果集的id放到查詢緩存中,第二次再次執行query.list()的時候,會把id拿出來,到相應的緩存去找,因為是跨session,在二級緩存中找不到,所以每次都會發出查詢語句,二級緩存中不存在,有多少個id就會發出查詢語句多少次。
### 七、開啟二級緩存,開啟查詢緩存,采用query.list()查詢實體
代碼如下所示。
~~~
/**
* 開啟查詢,開啟二級緩存,采用query.list()查詢實體
*
* 在兩個session中發query.list()查詢
*/
public voidtestCache6() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Liststudents = session.createQuery("select s from Student s")
.setCacheable(true)
.list();
for (int i=0;i<students.size(); i++) {
Studentstudnet = (Student)students.get(i);
System.out.println(studnet.getName());
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
System.out.println("-------------------------------------------------------");
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//不再發出查詢語句,因為配置了二級緩存和查詢緩存
Liststudents = session.createQuery("select s from Student s")
.setCacheable(true)
.list();
for (int i=0;i<students.size(); i++) {
Studentstudnet = (Student)students.get(i);
System.out.println(studnet.getName());
}
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
結果如下所示
Hibernate: select student0_.id as id0_,student0_.name as name0_, student0_.classesid as classesid0_ from t_studentstudent0_
只發出一次sql請求,當我們第一次執行query.list()會放到二級緩存中,和query緩存中。當我們第一次執行查詢時,會找到相應的id到緩存中查找,在二級緩存中存在,則直接從二級緩存中取出數據,不再向數據庫中發出sql語句。
### 八、查詢緩存總結
查詢緩存是緩存普通屬性結果集的,對實體對象的結果集會緩存id。查詢緩存的生命周期,當關聯的表發生修改時,查詢緩存的生命周期結束。
而開啟緩存的時候,我們就要去維護緩存,如果緩存和內存中的數據不一致的話,和數據不同步,可能給用戶顯示的是臟數據了。所以根據需要使用緩存機制。
- 前言
- Struts旅程(一)Struts簡介和原理
- struts旅程(二)Struts登錄示例
- Struts旅程(三)Struts表單處理器ActionForm(靜態動態)
- Struts旅程(四)MVC向struts MVC框架演變過程
- Struts旅程(五)struts控制器DispatchAction
- Struts旅程(六)Struts頁面轉發控制ActionForward和ActionMapping
- Hibernate旅程(一)Hibernate架構概述
- Hibernate旅程(二)Hibernate實例
- Hibernate旅程(三)Hibernate持久化對象的三個狀態
- Hibernate旅程(四)Hibernate對數據庫刪除、查找、更新操作
- Hibernate旅程(五)Hibernate映射--基本類映射和對象關系映射
- Hibernate旅程(六)Hibernate映射--繼承映射
- Hibernate旅程(七)Hibernate緩存機制--一級緩存
- Hibernate旅程(八)Hibernate緩存機制--二級緩存
- Hibernate旅程(九)Hibernate緩存機制--查詢緩存
- Spring旅程(一)為什么使用Spring
- Spring旅程(二)非Spring向Spring過渡-- Spring IOC容器的使用
- Spring旅程(三) AOP--Spring AOP容器基礎
- Spring旅程(四) AOP--Spring AOP實例
- SSH旅程(五)Spring運用到Hibernate中
- SSH旅程(六)Spring和struts結合(方案一)