第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Hibernate 入門教程 Hibernate 入門教程 Hibernate 性能之緩存與緩存算法

Hibernate 性能之緩存與緩存算法

1. 前言

本節(jié)課和大家一起聊聊查詢緩存和緩存算法。

對于緩存的使用要有針對性,不能濫用緩存,因為緩存本身是需要占用系統(tǒng)資源的,緩存的維護(hù)也需要消耗系統(tǒng)性能。

所以,這個世界是平衡的!如何掌握平衡,多用心感悟!

通過本節(jié)課程的學(xué)習(xí),你將了解到:

  • 什么是查詢緩存,如何使用查詢緩存;
  • 常用的緩存算法有哪些。

2. list()和 iterate()

在前面的課程里,咱們一起講解過 Query 對象,它提供了 list() 方法,此方法能接受 HQL 語句,查詢出開發(fā)者所需要的數(shù)據(jù)。

那么 list() 方法支持緩存嗎?也就是說 list() 方法查詢出來的數(shù)據(jù)會存儲到緩存中嗎?

本節(jié)課程中的緩存都是指二級緩存。

問題出來了,要找到答案很簡單,編寫一個實例,測試一下便知道結(jié)果 。創(chuàng)建 2 個 Session 對象,分別對同一個 HQL 語句進(jìn)行查詢:

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	System.out.println("------------------第一次查詢-------------------");
	List<Student> stus = query.list();
	System.out.println(stus.size());
	transaction.commit();
	} catch (Exception e) {
		transaction.rollback();
	} finally {
		session.close();
	}
	
session = sessionFactory.openSession();
transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	System.out.println("-----------------第二次查詢--------------------");
	List<Student> stus = query.list();
	System.out.println(stus.size());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

查看控制臺上的輸出結(jié)果:

Hibernate: 
    select
        student0_.stuId as stuId1_1_,
        student0_.classRoomId as classRoo5_1_,
        student0_.stuName as stuName2_1_,
        student0_.stuPassword as stuPassw3_1_,
        student0_.stuSex as stuSex4_1_ 
    from
        Student student0_
4
-----------------第二次查詢--------------------
Hibernate: 
    select
        student0_.stuId as stuId1_1_,
        student0_.classRoomId as classRoo5_1_,
        student0_.stuName as stuName2_1_,
        student0_.stuPassword as stuPassw3_1_,
        student0_.stuSex as stuSex4_1_ 
    from
        Student student0_
4

從結(jié)果上可以看出,兩次查詢的 HQL 請求是相同的,但每一次都會重新發(fā)送 SQL 語句,是不是就得出結(jié)論,list() 方法與緩存無緣分呢?

結(jié)論可不要提出來的太早。

Query 還提供了一個方法 iterate(),從功能上做比較,和 list() 沒有多大區(qū)別,只是一個返回的是集合對象,一個返回的是迭代器對象,作用是一樣的。

但是不是就沒有其它的區(qū)別了?

不急,先了解一下 iterate() 方法的特點,用實例來說話:

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	System.out.println("------------------迭代查詢-------------------");
	Iterator<Student> stus = query.iterate();
			
	while(stus.hasNext()) {
	    Student stu=	stus.next();
	    System.out.println("-------------------輸出結(jié)果------------------");
	    System.out.println("學(xué)生姓名:"+stu.getStuName());
	}	
		transaction.commit();
	} catch (Exception e) {
		transaction.rollback();
	} finally {
		session.close();
	}

截取運行后的一部分控制臺上的內(nèi)容展示如下:

------------------迭代查詢-------------------
Hibernate: 
    select
        student0_.stuId as col_0_0_ 
    from
        Student student0_
-------------------輸出結(jié)果------------------
Hibernate: 
    select
        student0_.stuId as stuId1_1_0_,
        student0_.classRoomId as classRoo5_1_0_,
        student0_.stuName as stuName2_1_0_,
        student0_.stuPassword as stuPassw3_1_0_,
        student0_.stuSex as stuSex4_1_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
學(xué)生姓名:Hibernate

當(dāng)我們執(zhí)行 iterate() 方法時,Hibernate 只是把所有的學(xué)生編號(主鍵)返回給應(yīng)用程序。也就是說并沒有返回完整的學(xué)生信息。

它為什么要這么做了?

首先有一點是可以得出結(jié)論的,僅僅得到學(xué)生編號肯定比獲取全部學(xué)生信息是要快很多的。

當(dāng)程序中需要學(xué)生其它數(shù)據(jù)的時候,這時 Hibernate 又會跑一次數(shù)據(jù)庫,根據(jù)前面獲取到的學(xué)生編號構(gòu)建新的條件查詢,從數(shù)據(jù)庫中再次獲取數(shù)據(jù)。

天呀,真不閑累的慌。

為什么要這么做了?

這有點類似于延遲加載,很多時候,程序中并不急著使用數(shù)據(jù),可能需要等某些依賴的邏輯成立后再使用。如此,iterate() 方法可快速獲取主鍵值,并安慰開發(fā)者,你看,我是有能力幫你獲取數(shù)據(jù)的。等需要更多時,我也是有能力拿到的。

Query 既提供 list() 方法,又提供 iterate() 方法不是沒有出發(fā)點的。這兩個方法很多時候結(jié)合起來使用,可以達(dá)到一種神奇的效果。

什么效果呢?

看一段實例:

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	System.out.println("------------------第一次使用 list()方法查詢-------------------");
	List<Student> stus = query.list();
	System.out.println(stus.size());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}
session = sessionFactory.openSession();
transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	System.out.println("-----------------第二次使用iterate()方法查詢--------------------");
	Iterator<Student> stus = query.iterate();
	while (stus.hasNext()) {
			Student stu = stus.next();
			System.out.println("-------------------輸出結(jié)果------------------");
			System.out.println("學(xué)生姓名:" + stu.getStuName());
	}
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

兩者結(jié)合,交織中所碰觸出的火花,你 get 到了嗎?

先使用 list() 方法查詢出所有學(xué)生信息, hibernate 會把 list() 方法查詢出來的數(shù)據(jù)全部存儲到緩存中。但是,它自己不使用緩存中自己緩存的數(shù)據(jù),它是勤勞的小蜜蜂,無私的奉獻(xiàn)。

誰會使用 list() 緩存的數(shù)據(jù)了?

輸出結(jié)果已經(jīng)告訴了我們答案,iterate() 方法會使用 list() 方法緩存的數(shù)據(jù)。

對于一條查詢語句,Iterator 會先從數(shù)據(jù)庫中找到所有符合條件的記錄的主鍵 ID,再通過主鍵 ID 去緩存找,對于緩存中沒有的記錄,再構(gòu)造語句從數(shù)據(jù)中查出,在緩存中沒有命中的話,效率很低。

那么,怎么聯(lián)合使用了?

建議在應(yīng)用程序啟動或修改時使用 list,通過 list 緩存數(shù)據(jù)。需要更多數(shù)據(jù)時再使用 iterator。

好兄弟,一輩子,江湖上,有你也有我。

3. 查詢緩存

是不是 list() 方法真的就不能使用緩存,而只是作為 iterator() 身后的兄弟。

Hibernate 中提供的有查詢緩存的概念。查詢緩存只對 query.list() 方法起作用。查詢緩存依賴于二級緩存,因此一定要打開二級緩存。而且,在默認(rèn)情況下,查詢緩存也是關(guān)閉的。

啟動查詢緩存

  1. 在 Hibernate 的主配置文件中添加如下配置信息:
<property name="cache.use_query_cache">true</property>

切記,使用查詢緩存是一定要加入下面的代碼:

query.setCacheable(true);

好吧,來一個實例,看看查詢緩存的威力。

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	query.setCacheable(true);
	System.out.println("------------------第一次查詢-------------------");
	List<Student> stus = query.list();
	System.out.println(stus.size());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

session = sessionFactory.openSession();
transaction = null;
try {
	transaction = session.beginTransaction();
	String hql = "from Student s";
	Query query = session.createQuery(hql);
	query.setCacheable(true);
	System.out.println("-----------------第二次查詢--------------------");
	List<Student> stus = query.list();
	System.out.println(stus.size());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

查看一下控制臺上的輸出結(jié)果:

------------------第一次查詢-------------------
Hibernate: 
    select
        student0_.stuId as stuId1_1_,
        student0_.classRoomId as classRoo5_1_,
        student0_.stuName as stuName2_1_,
        student0_.stuPassword as stuPassw3_1_,
        student0_.stuSex as stuSex4_1_ 
    from
        Student student0_
4
-----------------第二次查詢--------------------
4

結(jié)論很明顯,第一次使用 list() 方法時,需要發(fā)送 SQL 語句,第二次時,就不再需要了,也就是說 list() 也是可以享受自己緩存的數(shù)據(jù)。但是必須啟動查詢緩存,且在代碼中明明確確指示出來。

4. 緩存算法

什么是緩存算法?

緩存是一個臨時存儲數(shù)據(jù)的地方,但是,這個地方可金貴的很,咱們可不能讓那些不經(jīng)常使用的、過期的數(shù)據(jù)長時間待在里面。所以,必須有一種機(jī)制能隨時檢查一下緩存中的數(shù)據(jù),哪些數(shù)據(jù)是可以繼續(xù)待在里面的,哪些數(shù)據(jù)需要移出去,給新來者挪出空間的,這就是所謂的緩存算法。

常用的緩存算法:

  • LRU : Least Recently Used ,最近最少被使用的,每個緩存對象都記錄一個最后使用時間;
  • LFU : Least Frequently Used ,最近使用頻率最少;
  • FIFO: First in First Out ,這個簡單,定時清理時,先來的,先離開。

SessionSessionFactory 對象也提供的有與緩存管理有關(guān)的方法,方便開發(fā)者可以隨時按需清除緩存。如 evict() 等方法。
上一節(jié)課介紹 EHCache 緩存框架時,就要使用它的配置文件,其配置內(nèi)容就是設(shè)置如何管理緩存。

5. 小結(jié)

好了!又到了說再見的時候了,本節(jié)課繼續(xù)上一節(jié)的內(nèi)容,向大家介紹了查詢緩存,主要介紹了 Query 對象的 listiterate 兩個方法,它們有各自的特點,也有各自調(diào)用的時機(jī)點。

聯(lián)合使用兩者,能更充分的發(fā)揮緩存的功效。

后面也給大家介紹了緩存算法,大家需要把此內(nèi)容當(dāng)成常識性知識。