日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

hibernate缓存机制详细介绍

發(fā)布時(shí)間:2025/4/16 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hibernate缓存机制详细介绍 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

hibernate的緩存機(jī)制,包括一級(jí)緩存(session級(jí)別)、二級(jí)緩存(sessionFactory級(jí)別)。

一:hibernate的 N+1問(wèn)題

list()獲得對(duì)象:

如果通過(guò)list()方法來(lái)獲得對(duì)象,毫無(wú)疑問(wèn),hibernate會(huì)發(fā)出一條sql語(yǔ)句,將所有的對(duì)象查詢出來(lái),這點(diǎn)相信大家都能理解

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.rid as rid2_, student0_.sex as sex2_ from t_student student0_ limit ?

?

那么,我們?cè)賮?lái)看看iterator()這種情況

iterator()獲得對(duì)象

在執(zhí)行完上述的測(cè)試用例后,我們來(lái)看看控制臺(tái)的輸出,看會(huì)發(fā)出多少條 sql 語(yǔ)句:

?

我們看到,當(dāng)如果通過(guò)iterator()方法來(lái)獲得我們對(duì)象的時(shí)候,hibernate首先會(huì)發(fā)出1條sql去查詢出所有對(duì)象的 id 值,當(dāng)我們?nèi)绻枰樵兊侥硞€(gè)對(duì)象的具體信息的時(shí)候,hibernate此時(shí)會(huì)根據(jù)查詢出來(lái)的 id 值再發(fā)sql語(yǔ)句去從數(shù)據(jù)庫(kù)中查詢對(duì)象的信息,這就是典型的?N+1?的問(wèn)題。

那么這種 N+1 問(wèn)題我們?nèi)绾谓鉀Q呢,其實(shí)我們只需要使用 list() 方法來(lái)獲得對(duì)象即可。但是既然可以通過(guò) list() 我們就不會(huì)出現(xiàn) N+1的問(wèn)題,那么我們?yōu)槭裁催€要保留 iterator()這種形式呢?我們考慮這樣一種情況,如果我們需要在一個(gè)session當(dāng)中要兩次查詢出很多對(duì)象,此時(shí)我們?nèi)绻麑?xiě)兩條 list()時(shí),hibernate此時(shí)會(huì)發(fā)出兩條 sql 語(yǔ)句,而且這兩條語(yǔ)句是一樣的,但是我們?nèi)绻谝粭l語(yǔ)句使用 list(),而第二條語(yǔ)句使用 iterator()的話,此時(shí)我們也會(huì)發(fā)兩條sql語(yǔ)句,但是第二條語(yǔ)句只會(huì)將查詢出對(duì)象的id,所以相對(duì)應(yīng)取出所有的對(duì)象而已,顯然這樣可以節(jié)省內(nèi) 存,而如果再要獲取對(duì)象的時(shí)候,因?yàn)榈谝粭l語(yǔ)句已經(jīng)將對(duì)象都查詢出來(lái)了,此時(shí)會(huì)將對(duì)象保存到session的一級(jí)緩存中去,所以再次查詢時(shí),就會(huì)首先去緩 存中查找,如果找到,則不發(fā)sql語(yǔ)句了。這里就牽涉到了接下來(lái)這個(gè)概念:hibernate的一級(jí)緩存。

二、一級(jí)緩存(session級(jí)別)

我們來(lái)看看hibernate提供的一級(jí)緩存:

我們來(lái)看看控制臺(tái)輸出:

?

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.rid as rid2_,
student0_.sex as sex2_ from t_student student0_ limit ?

我們看到此時(shí)hibernate僅僅只會(huì)發(fā)出一條 sql 語(yǔ)句,因?yàn)榈谝恍写a就會(huì)將整個(gè)的對(duì)象查詢出來(lái),放到session的一級(jí)緩存中去,當(dāng)我如果需要再次查詢學(xué)生對(duì)象時(shí),此時(shí)首先會(huì)去緩存中看是否存在該對(duì) 象,如果存在,則直接從緩存中取出,就不會(huì)再發(fā)sql了,但是要注意一點(diǎn):hibernate的一級(jí)緩存是session級(jí)別的,所以如果session關(guān)閉后,緩存就沒(méi)了,此時(shí)就會(huì)再次發(fā)sql去查數(shù)據(jù)庫(kù)

?

Hibernate: select student0_.id as id2_2_, student0_.name as name2_2_, student0_.sex as sex2_2_, student0_.rid as rid2_2_, classroom1_.id as id1_0_, classroom1_.name as name1_0_, classroom1_.sid as sid1_0_, special2_.id as id0_1_, special2_.name as name0_1_, special2_.type as type0_1_ from t_student student0_ left outer join t_classroom classroom1_ on student0_.rid=classroom1_.id left outer join t_special special2_ on classroom1_.sid=special2_.id where student0_.id=?

我們看到此時(shí)會(huì)發(fā)出兩條sql語(yǔ)句,因?yàn)閟ession關(guān)閉以后,一級(jí)緩存就不存在了,所以如果再查詢的時(shí)候,就會(huì)再發(fā)sql。要解決這種問(wèn)題,我們應(yīng)該怎么做呢?這就要我們來(lái)配置hibernate的二級(jí)緩存了,也就是sessionFactory級(jí)別的緩存。

三、二級(jí)緩存(sessionFactory級(jí)別)

?

使用hibernate二級(jí)緩存,我們首先需要對(duì)其進(jìn)行配置,配置步驟如下:

1.hibernate并沒(méi)有提供相應(yīng)的二級(jí)緩存的組件,所以需要加入額外的二級(jí)緩存包,常用的二級(jí)緩存包是EHcache。這個(gè)我們?cè)谙螺d好的 hibernate的lib->optional->ehcache下可以找到(我這里使用的hibernate4.1.7版本),然后將里 面的幾個(gè)jar包導(dǎo)入即可。

2.在hibernate.cfg.xml配置文件中配置我們二級(jí)緩存的一些屬性:

我這里使用的是hibernate4.1.7版本,如果是使用hibernate3的版本的話,那么二級(jí)緩存的提供類則要配置成這個(gè):

3.配置hibernate的二級(jí)緩存是通過(guò)使用 ehcache的緩存包,所以我們需要?jiǎng)?chuàng)建一個(gè) ehcache.xml 的配置文件,來(lái)配置我們的緩存信息,將其放到項(xiàng)目根目錄下

?

這樣我們的二級(jí)緩存配置就算完成了,接下來(lái)我們來(lái)通過(guò)測(cè)試用例測(cè)試下我們的二級(jí)緩存是否起作用

①二級(jí)緩存是sessionFactory級(jí)別的緩存

TestCase1:

?

因?yàn)槎?jí)緩存是sessionFactory級(jí)別的緩存,我們看到,在配置了二級(jí)緩存以后,當(dāng)我們session關(guān)閉以后,我們?cè)偃ゲ樵儗?duì)象的時(shí)候,此時(shí)hibernate首先會(huì)去二級(jí)緩存中查詢是否有該對(duì)象,有就不會(huì)再發(fā)sql了。

②二級(jí)緩存緩存的僅僅是對(duì)象,如果查詢出來(lái)的是對(duì)象的一些屬性,則不會(huì)被加到緩存中去

TestCase2:

?

我們看到這個(gè)測(cè)試用例,如果我們只是取出對(duì)象的一些屬性的話,則不會(huì)將其保存到二級(jí)緩存中去,因?yàn)?strong>二級(jí)緩存緩存的僅僅是對(duì)象。

③通過(guò)二級(jí)緩存來(lái)解決 N+1 的問(wèn)題

TestCase3:

?

?

當(dāng)我們?nèi)绻枰樵兂鰞纱螌?duì)象的時(shí)候,可以使用二級(jí)緩存來(lái)解決N+1的問(wèn)題。

④二級(jí)緩存會(huì)緩存 hql 語(yǔ)句嗎?

TestCase4:

?

?

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ limit ? Hibernate: select student0_.id as id2_, student0_.name as name2_,student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ limit ? 我們看到,當(dāng)我們?nèi)绻ㄟ^(guò) list() 去查詢兩次對(duì)象時(shí),二級(jí)緩存雖然會(huì)緩存查詢出來(lái)的對(duì)象,但是我們看到發(fā)出了兩條相同的查詢語(yǔ)句,這是因?yàn)槎?jí)緩存不會(huì)緩存我們的hql查詢語(yǔ)句,要想解決這個(gè)問(wèn)題,我們就要配置我們的查詢緩存了。

  

四、查詢緩存(sessionFactory級(jí)別)

我們?nèi)绻渲貌樵兙彺?#xff0c;只需要在hibernate.cfg.xml中加入一條配置即可:

?

然后我們?nèi)绻诓樵僪ql語(yǔ)句時(shí)要使用查詢緩存,就需要在查詢語(yǔ)句后面設(shè)置這樣一個(gè)方法:

?

如果是在annotation中,我們還需要在這個(gè)類上加上這樣一個(gè)注解:@Cacheable

接下來(lái)我們來(lái)通過(guò)測(cè)試用例來(lái)看看我們的查詢緩存

①查詢緩存也是sessionFactory級(jí)別的緩存

TestCase1:

?

?

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ limit ? 我們看到,此時(shí)如果我們發(fā)出兩條相同的語(yǔ)句,hibernate也只會(huì)發(fā)出一條sql,因?yàn)橐呀?jīng)開(kāi)啟了查詢緩存了,并且查詢緩存也是sessionFactory級(jí)別的 ②只有當(dāng) HQL 查詢語(yǔ)句完全相同時(shí),連參數(shù)設(shè)置都要相同,此時(shí)查詢緩存才有效 TestCase2:

  

?

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ where student0_.name like ? limit ? Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ where student0_.name like ? limit ?我們看到,如果我們的hql查詢語(yǔ)句不同的話,我們的查詢緩存也沒(méi)有作用 ③查詢緩存也能引起 N+1 的問(wèn)題 查詢緩存也能引起 N+1 的問(wèn)題,我們這里首先先將 Student 對(duì)象上的二級(jí)緩存先注釋掉:

  

?

TestCase4:

?

?

Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ where student0_.name like ? limit ?Hibernate: select student0_.id as id2_2_, student0_.name as name2_2_, student0_.sex as sex2_2_, student0_.rid as rid2_2_, classroom1_.id as id1_0_, classroom1_.name as name1_0_, classroom1_.sid as sid1_0_, special2_.id as id0_1_, special2_.name as name0_1_, special2_.type as type0_1_ from t_student student0_ left outer join t_classroom classroom1_ on student0_.rid=classroom1_.id left outer join t_special special2_ on classroom1_.sid=special2_.id where student0_.id=?Hibernate: select student0_.id as id2_2_, student0_.name as name2_2_, student0_.sex as sex2_2_, student0_.rid as rid2_2_, classroom1_.id as id1_0_, classroom1_.name as name1_0_, classroom1_.sid as sid1_0_, special2_.id as id0_1_, special2_.name as name0_1_, special2_.type as type0_1_ from t_student student0_ left outer join t_classroom classroom1_ on student0_.rid=classroom1_.id left outer join t_special special2_ on classroom1_.sid=special2_.id where student0_.id=?Hibernate: select student0_.id as id2_2_, student0_.name as name2_2_, student0_.sex as sex2_2_, student0_.rid as rid2_2_, classroom1_.id as id1_0_, classroom1_.name as name1_0_, classroom1_.sid as sid1_0_, special2_.id as id0_1_, special2_.name as name0_1_, special2_.type as type0_1_ from t_student student0_ left outer join t_classroom classroom1_ on student0_.rid=classroom1_.id left outer join t_special special2_ on classroom1_.sid=special2_.id where student0_.id=?Hibernate: select student0_.id as id2_2_, student0_.name as name2_2_, student0_.sex as sex2_2_, student0_.rid as rid2_2_, classroom1_.id as id1_0_, classroom1_.name as name1_0_, classroom1_.sid as sid1_0_, special2_.id as id0_1_, special2_.name as name0_1_, special2_.type as type0_1_ from t_student student0_ left outer join t_classroom classroom1_ on student0_.rid=classroom1_.id left outer join t_special special2_ on classroom1_.sid=special2_.id where student0_.id=?

  

我們看到,當(dāng)我們將二級(jí)緩存注釋掉以后,在使用查詢緩存時(shí),也會(huì)出現(xiàn) N+1 的問(wèn)題,為什么呢?

因?yàn)?strong>查詢緩存緩存的也僅僅是對(duì)象的id,所以第一條 sql 也是將對(duì)象的id都查詢出來(lái),但是當(dāng)我們后面如果要得到每個(gè)對(duì)象的信息的時(shí)候,此時(shí)又會(huì)發(fā)sql語(yǔ)句去查詢,所以,如果要使用查詢緩存,我們一定也要開(kāi)啟我們的二級(jí)緩存,這樣就不會(huì)出現(xiàn) N+1 問(wèn)題了

?

轉(zhuǎn)載于:https://www.cnblogs.com/ipetergo/p/6803290.html

總結(jié)

以上是生活随笔為你收集整理的hibernate缓存机制详细介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。