摘要:通過(guò)查詢實(shí)例調(diào)用上面的方法這里就算方法體里面執(zhí)行三個(gè)查詢操作,也只會(huì)執(zhí)行一條查詢,因?yàn)槭褂玫耐粋€(gè)對(duì)象,這就有使用到的一級(jí)緩存。方法會(huì)使用二級(jí)緩存,而方法在一級(jí)緩存沒(méi)有找到的情況下會(huì)直接查詢數(shù)據(jù)庫(kù),不會(huì)去二級(jí)緩存中查找。
一、什么是緩存
緩存是內(nèi)存中少部分?jǐn)?shù)據(jù)的復(fù)制品,所以CPU到緩存中尋找數(shù)據(jù)時(shí),也會(huì)出現(xiàn)找不到的情況(因?yàn)檫@些數(shù)據(jù)沒(méi)有從內(nèi)存復(fù)制到緩存中去),這時(shí)CPU還是會(huì)到內(nèi)存中去找數(shù)據(jù),這樣系統(tǒng)的速率就慢下來(lái)了,不過(guò)CPU會(huì)把這些數(shù)據(jù)復(fù)制到緩存中去,以便下一次不要再到內(nèi)存中去取。
二、Hibernate的一級(jí)緩存
(1)使用
Hibernate的一級(jí)緩存是默認(rèn)開(kāi)啟的,當(dāng)獲取到一個(gè)Session對(duì)象,并執(zhí)行save、update、saveOrUpdate、get方法時(shí)就會(huì)用到Hibernate一級(jí)緩存,當(dāng)然也可以調(diào)用清除的放方法,Session為清除緩存提供了clear(清除所有的一級(jí)緩存)、evict(清除實(shí)例對(duì)象緩存)、refresh(重新查詢數(shù)據(jù)并刷新緩存)。
例子:
//泛型查詢實(shí)例 public E find(S s) { //使用Spring 獲取一個(gè)Session對(duì)象 Session session = getSession(); //執(zhí)行查詢操作 E bean = (E)session.get(entityClass, (Serializable) s); //清除實(shí)例對(duì)象緩存 session.evict(bean); //返回查詢的對(duì)象 return bean; }
(2)狀態(tài)
Hibernate緩存狀態(tài)分為瞬時(shí)狀態(tài)、持久狀態(tài)、脫管狀態(tài)。
瞬時(shí)狀態(tài): 創(chuàng)建一個(gè)POJO,還未將對(duì)象數(shù)據(jù)保存到數(shù)據(jù)庫(kù)時(shí),Session中也沒(méi)有當(dāng)前POJO實(shí)例。
例子:
//創(chuàng)建一個(gè)POJO實(shí)例 Account account = new Account(); //給實(shí)例添加數(shù)據(jù) account.setPhone("12345678931"); //這時(shí)實(shí)例并沒(méi)有保存
持久狀態(tài): POJO對(duì)象被添加到Session緩存中,數(shù)據(jù)庫(kù)也要有對(duì)應(yīng)的數(shù)據(jù)。
例子:
public Integer saveStatus(Account entity) { //獲取Session對(duì)象 Session session = getSession(); //執(zhí)行保存方法 Integer id = (Integer)session.save(entity); //修改被持久化的POJO對(duì)象 entity.setState(4); //返回對(duì)象ID return id; }
在上面的例子中,當(dāng)保存事務(wù)還未提交,這時(shí)數(shù)據(jù)已經(jīng)被持久化。這里會(huì)執(zhí)行兩條SQL,一條添加SQL,一條修改SQL(并沒(méi)有調(diào)用修改方法為什么會(huì)執(zhí)行修改SQL呢?因?yàn)镠ibernate被持久化的POJO對(duì)象在被重新賦值時(shí)會(huì)觸發(fā)更新操作。)
脫管狀態(tài): 在緩存中已經(jīng)被持久化的POJO對(duì)象,接著POJO對(duì)象執(zhí)行了evict方法,這時(shí)POJO對(duì)象會(huì)從緩存中托管,但數(shù)據(jù)庫(kù)中是有對(duì)應(yīng)的數(shù)據(jù)。
例子:
public Integer saveStatus(Account entity) { //獲取Session對(duì)象 Session session = getSession(); //執(zhí)行保存方法 Integer id = (Integer)session.save(entity); //脫管當(dāng)前POJO對(duì)象 session.evict(entity); //修改被持久化的POJO對(duì)象 entity.setState(4); //返回對(duì)象ID return id; }
調(diào)用evict方法將POJO對(duì)象傳入,清除實(shí)例的持久化,修改POJO實(shí)例將不會(huì)在觸發(fā)更新操作。
(3)緩存綁定
Hibernate的一級(jí)緩存是綁定Session的,當(dāng)獲取到一個(gè)Session對(duì)象,在執(zhí)行Sessinon里面的方法都能使用Hibernate默認(rèn)提供的一級(jí)緩存,執(zhí)行完成Session對(duì)象消亡即緩存數(shù)據(jù)也跟著消亡(一級(jí)緩存的數(shù)據(jù)是放在棧中)。
例子:
//通過(guò)id查詢POJO實(shí)例 public E find(S s) { Session session = getSession(); E bean = (E)session.get(entityClass, (Serializable) s); return bean; } //調(diào)用三次上面的方法 accountService.find(1); accountService.find(1); accountService.find(1);
這里會(huì)執(zhí)行三條查詢SQL,這是因?yàn)槔锩娅@取的Session對(duì)象是線程安全的,彼此并沒(méi)有任何關(guān)聯(lián)(這也是為什么Spring不能用到Hibernate的一級(jí)緩存,其實(shí)不是Spring的問(wèn)題)。
//通過(guò)id查詢POJO實(shí)例 public E find(S s) { Session session = getSession(); E bean = (E)session.get(entityClass, (Serializable) s); E bean1 = (E)session.get(entityClass, (Serializable) s); E bean2 = (E)session.get(entityClass, (Serializable) s); return bean; } //調(diào)用上面的方法 accountService.find(1);
這里就算方法體里面執(zhí)行三個(gè)查詢操作,也只會(huì)執(zhí)行一條查詢SQL,因?yàn)槭褂玫耐粋€(gè)Session對(duì)象,這就有使用到Hibernate的一級(jí)緩存。
二、Hibernate的二級(jí)緩存
(1)使用
Hibernate的二級(jí)緩存是默認(rèn)關(guān)閉的(二級(jí)緩存的數(shù)據(jù)是放在堆中),如果需要開(kāi)啟二級(jí)緩存則需要額外的配置。
(2)配置
第一步:POJO對(duì)象設(shè)置
@Entity//POJO注解 @Table(name = "account")//對(duì)應(yīng)的數(shù)據(jù)庫(kù)表名稱 @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)//二級(jí)緩存配置,讀寫模式 public class Account { ... }
第二步:配置Hibernate session工廠
update org.hibernate.dialect.MySQLDialect true true true true org.hibernate.cache.ehcache.EhCacheRegionFactory classpath:applicationContext-ehcache.xml
com.test.entity
第三步:創(chuàng)建二級(jí)緩存配置文件
//maxElementsInMemory--緩存對(duì)象的最大數(shù)目 //eternal--對(duì)象是否永不過(guò)期,設(shè)置為true,過(guò)期時(shí)間則無(wú)效 //timeToldleSeconds--對(duì)象空閑多長(zhǎng)時(shí)間未被使用就失效 //timeToLiveSeconds--對(duì)象被緩存的時(shí)間 //overflowToDisk--內(nèi)存溢出時(shí)是否刷盤,如果為true則需要配置一個(gè)刷盤路徑 //diskExpiryThreadIntervalSeconds--磁盤失效線程運(yùn)行時(shí)間間隔
三、選擇正確的方法
(1) Hibernatne查詢分為兩類:一類是得到單個(gè)對(duì)象,另一類是得到結(jié)果集。
單個(gè)對(duì)象:
get()方法和load()方法的區(qū)別在于對(duì)二級(jí)緩存的使用上。load()方法會(huì)使用二級(jí)緩存,而get()方法在一級(jí)緩存沒(méi)有找到的情況下會(huì)直接查詢數(shù)據(jù)庫(kù),不會(huì)去二級(jí)緩存中查找。在使用中,對(duì)使用了二級(jí)緩存的對(duì)象進(jìn)行查詢時(shí)最好使用load()方法,以充分利用二級(jí)緩存來(lái)提高檢索的效率。
結(jié)果集對(duì)象:
list方法介紹
list()方法在執(zhí)行時(shí),是直接運(yùn)行查詢結(jié)果所需要的查詢語(yǔ)句,而iterator()方法則是先執(zhí)行得到對(duì)象ID的查詢,然后再根據(jù)每個(gè)ID值去取得所要查詢的對(duì)象。因此,對(duì)于list()方式的查詢通常只會(huì)執(zhí)行一個(gè)SQL語(yǔ)句,而對(duì)于iterator()方法的查詢則可能需要執(zhí)行N+1條SQL語(yǔ)句(N為結(jié)果集中的記錄數(shù))。
list()方法只能使用二級(jí)緩存中的查詢緩存,而無(wú)法使用二級(jí)緩存對(duì)單個(gè)對(duì)象的緩存(但是會(huì)把查詢出的對(duì)象放入二級(jí)緩存中)。所以,除非重復(fù)執(zhí)行相同的查詢操作,否則無(wú)法利用緩存的機(jī)制來(lái)提高查詢的效率。
list()方法會(huì)一次獲得所有的結(jié)果集對(duì)象,而且它會(huì)依據(jù)查詢的結(jié)果初始化所有的結(jié)果集對(duì)象。這在結(jié)果集非常大的時(shí)候必然會(huì)占據(jù)非常多的內(nèi)存,甚至?xí)斐蓛?nèi)存溢出情況的發(fā)生。
iterator方法介紹
iterator()方法只是可能執(zhí)行N+1條數(shù)據(jù),具體執(zhí)行SQL語(yǔ)句的數(shù)量取決于緩存的情況以及對(duì)結(jié)果集的訪問(wèn)情況。
iterator()方法則可以充分利用二級(jí)緩存,在根據(jù)ID檢索對(duì)象的時(shí)候會(huì)首先到緩存中查找,只有在找不到的情況下才會(huì)執(zhí)行相應(yīng)的查詢語(yǔ)句。所以,緩存中對(duì)象的存在與否會(huì)影響到SQL語(yǔ)句的執(zhí)行數(shù)量。
iterator()方法在執(zhí)行時(shí)不會(huì)一次初始化所有的對(duì)象,而是根據(jù)對(duì)結(jié)果集的訪問(wèn)情況來(lái)初始化對(duì)象。因此在訪問(wèn)中可以控制緩存中對(duì)象的數(shù)量,以避免占用過(guò)多緩存,導(dǎo)致內(nèi)存溢出情況的發(fā)生。使用iterator()方法的另外一個(gè)好處是,如果只需要結(jié)果集中的部分記錄,那么沒(méi)有被用到的結(jié)果對(duì)象根本不會(huì)被初始化。所以,對(duì)結(jié)果集的訪問(wèn)情況也是調(diào)用iterator()方法時(shí)執(zhí)行數(shù)據(jù)庫(kù)SQL語(yǔ)句多少的一個(gè)因素。
部分信息來(lái)自網(wǎng)絡(luò),歡迎大家指出錯(cuò)誤。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/62023.html
摘要:通過(guò)查詢實(shí)例調(diào)用上面的方法這里就算方法體里面執(zhí)行三個(gè)查詢操作,也只會(huì)執(zhí)行一條查詢,因?yàn)槭褂玫耐粋€(gè)對(duì)象,這就有使用到的一級(jí)緩存。方法會(huì)使用二級(jí)緩存,而方法在一級(jí)緩存沒(méi)有找到的情況下會(huì)直接查詢數(shù)據(jù)庫(kù),不會(huì)去二級(jí)緩存中查找。 一、什么是緩存 緩存是內(nèi)存中少部分?jǐn)?shù)據(jù)的復(fù)制品,所以CPU到緩存中尋找數(shù)據(jù)時(shí),也會(huì)出現(xiàn)找不到的情況(因?yàn)檫@些數(shù)據(jù)沒(méi)有從內(nèi)存復(fù)制到緩存中去),這時(shí)CPU還是會(huì)到內(nèi)存中去...
摘要:中怎樣實(shí)現(xiàn)類之間的關(guān)系如一對(duì)多多對(duì)多的關(guān)系中怎樣實(shí)現(xiàn)類之間的關(guān)系如一對(duì)多多對(duì)多的關(guān)系它們通過(guò)配置文件中的來(lái)實(shí)現(xiàn)類之間的關(guān)聯(lián)關(guān)系的。 Hibernate常見(jiàn)面試題 Hibernate工作原理及為什么要用? Hibernate工作原理及為什么要用? 讀取并解析配置文件 讀取并解析映射信息,創(chuàng)建SessionFactory 打開(kāi)Sesssion 創(chuàng)建事務(wù)Transation 持久化操作 提...
摘要:一級(jí)緩存又叫的緩存,是事物范圍的緩存,默認(rèn)開(kāi)啟二級(jí)緩存又叫的緩存,默認(rèn)關(guān)閉。二級(jí)緩存存放數(shù)據(jù)一般是不經(jīng)常修改的數(shù)據(jù),不會(huì)被并發(fā)訪問(wèn)的數(shù)據(jù),常量數(shù)據(jù)訪問(wèn)數(shù)據(jù)順序是一級(jí)緩存二級(jí)緩存數(shù)據(jù)庫(kù)。 Hibernate與mybatis比較 1、先說(shuō)底層: a)Jdbc:全稱java數(shù)據(jù)庫(kù)連接,是java語(yǔ)言用來(lái)規(guī)范客戶端如何訪問(wèn)數(shù)據(jù)庫(kù)的程序接口。 b) 一般步驟: i.加載驅(qū)動(dòng)程序 ...
摘要:使用反射機(jī)制,而不是字節(jié)碼增強(qiáng)程序來(lái)實(shí)現(xiàn)透明性。工具類初始化失敗為空,請(qǐng)檢查配置文件瞬時(shí)對(duì)象與持久化對(duì)象測(cè)試代碼當(dāng)前在數(shù)據(jù)庫(kù)中沒(méi)有記錄進(jìn)行關(guān)聯(lián),所以此時(shí)是瞬時(shí)對(duì)象。將持久化當(dāng)前在數(shù)據(jù)庫(kù)有唯一一條記錄對(duì)應(yīng),所以此時(shí)是持久化對(duì)象。 showImg(https://segmentfault.com/img/bVbo4at?w=2313&h=642); 一、什么是Hibernate? Hibe...
摘要:面試總結(jié)最近兩周面試了幾家公司高級(jí)工程師的職位,主要有宜信網(wǎng)信金融阿里高德口袋購(gòu)物。目前有部分公司已經(jīng)面試通過(guò),兩家在等消息。今天趁熱把常見(jiàn)面試內(nèi)容總結(jié)一下。可以用來(lái)完成統(tǒng)一命名服務(wù)狀態(tài)同步服務(wù)集群管理分布式應(yīng)用配置項(xiàng)等管理工作。 面試總結(jié) 最近兩周面試了幾家公司Java高級(jí)工程師的職位,主要有宜信、網(wǎng)信金融、阿里高德、口袋購(gòu)物。目前有部分公司已經(jīng)面試通過(guò),兩家在等消息。今天趁熱把常見(jiàn)...
閱讀 2108·2021-11-18 10:02
閱讀 2861·2021-09-04 16:41
閱讀 1153·2019-08-30 15:55
閱讀 1416·2019-08-29 17:27
閱讀 1094·2019-08-29 17:12
閱讀 2538·2019-08-29 15:38
閱讀 2862·2019-08-29 13:02
閱讀 2838·2019-08-29 12:29