hibernate查詢緩存詳細分析
一、查詢緩存配置
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("-------------------------------------------------------");
//不會發(fā)出查詢語句,因為啟用查詢緩存
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_
由此可知,我們開啟了查詢緩存,第一次進行查詢的時候,已經(jīng)把結果放到querycache中,當?shù)诙卧俅巫龀鱿嗤牟樵兊臅r候,就不再向數(shù)據(jù)庫發(fā)重復的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();
//不會發(fā)出查詢語句,因為查詢緩存和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…
我們可以看出,同樣,只打印一次查詢語句,如果沒有開啟查詢緩存的話,并且關閉二級緩存的情況下,還會去數(shù)據(jù)庫再查詢一遍,而我們的程序中沒有再去重復的去數(shù)據(jù)庫中查詢的原因是,當開啟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();
//會發(fā)出查詢語句,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_
根據(jù)這樣的結果我們發(fā)現(xiàn),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();
//會發(fā)出查詢語句,默認query.list()每次執(zhí)行都會發(fā)出查詢語句
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每次執(zhí)行都會發(fā)出查詢語句。
六、關閉二級緩存,開啟查詢緩存,采用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();
//會發(fā)出n條查詢語句,因為開啟了查詢緩存,關閉了二級緩存,那么查詢緩存就會緩存實體對象的id
//第二次執(zhí)行query.list(),將查詢緩存中的id依次取出,分別到一級緩存和二級緩存中查詢相應的實體
//對象,如果存在就使用緩存中的實體對象,否則根據(jù)id發(fā)出查詢學生的語句
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如下圖所示。

在第一次查詢的時候,發(fā)出一條sql語句查詢出結果,因為我們開啟了查詢緩存,會把第一次查詢出的實體結果集的id放到查詢緩存中,第二次再次執(zhí)行query.list()的時候,會把id拿出來,到相應的緩存去找,因為是跨session,在二級緩存中找不到,所以每次都會發(fā)出查詢語句,二級緩存中不存在,有多少個id就會發(fā)出查詢語句多少次。
七、開啟二級緩存,開啟查詢緩存,采用query.list()查詢實體
代碼如下所示。
/**
* 開啟查詢,開啟二級緩存,采用query.list()查詢實體
*
* 在兩個session中發(fā)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();
//不再發(fā)出查詢語句,因為配置了二級緩存和查詢緩存
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_
只發(fā)出一次sql請求,當我們第一次執(zhí)行query.list()會放到二級緩存中,和query緩存中。當我們第一次執(zhí)行查詢時,會找到相應的id到緩存中查找,在二級緩存中存在,則直接從二級緩存中取出數(shù)據(jù),不再向數(shù)據(jù)庫中發(fā)出sql語句。
八、查詢緩存總結
查詢緩存是緩存普通屬性結果集的,對實體對象的結果集會緩存id。查詢緩存的生命周期,當關聯(lián)的表發(fā)生修改時,查詢緩存的生命周期結束。
而開啟緩存的時候,我們就要去維護緩存,如果緩存和內存中的數(shù)據(jù)不一致的話,和數(shù)據(jù)不同步,可能給用戶顯示的是臟數(shù)據(jù)了。所以根據(jù)需要使用緩存機制。
總結
以上所述是小編給大家介紹的hibernate查詢緩存詳細分析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
詳解MybatisPlus中@TableLogic注解的使用
@TableLogic一般用于實現(xiàn)數(shù)據(jù)庫數(shù)據(jù)邏輯刪除,本文我們將介紹 @TableLogic 注解的用法,以及每個屬性的實際意義和用法,感興趣的可以了解一下2022-06-06
Springboot實現(xiàn)前后端分離excel下載
這篇文章主要介紹了Springboot實現(xiàn)前后端分離excel下載,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
Java安全 ysoserial CommonsCollections2示例分析
這篇文章主要為大家介紹了Java安全 ysoserial CommonsCollections2示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
SpringBoot中web模版數(shù)據(jù)渲染展示的案例詳解
憑借 Spring Framework 的模塊、與你最喜歡的工具的大量集成以及插入你自己的功能的能力,Thymeleaf 是現(xiàn)代 HTML5 JVM Web 開發(fā)的理想選擇——盡管它還有更多功能,本文重點給大家介紹SpringBoot中web模版數(shù)據(jù)渲染展示,需要的朋友可以參考下2022-01-01
詳解在spring boot中配置多個DispatcherServlet
本篇文章主要介紹了詳解在spring boot中配置多個DispatcherServlet,具有一定的參考價值,有興趣的可以了解一下。2017-03-03

