2016-09-14 152 views
1

看起來很簡單的問題。我試了很多,但失敗了。使用休眠一級緩存

據我所知,Hibernate一級緩存意味着會話級緩存。當我們在同一會話中多次檢索同一對象時,它將從緩存中檢索。

例如,我在數據庫中有一個ID爲100的員工記錄。

我打開了一個會話並獲得該員工對象。直到我關閉會話該對象在同一會話中可用。

問題:爲什麼我需要在同一個會話中多次檢索同一對象(任何它在會話中的可用狀態,直到關閉它爲止)?

回答

1

據我所知,Hibernate一級緩存意味着會話級緩存。當我們在同一會話中多次檢索同一對象時,它將從緩存中檢索。

它是一半正確的。除了你所說的,一級緩存的一個主要原因是,在同一會話下,Hibernate將確保相同的實體(具有相同ID的實體)將由相同的對象實例表示。

你說的是正確的只有當你從會議通過ID獲取實體:

Foo foo1 = session.get(Foo.class, 1L); 
Foo foo2 = session.get(Foo.class, 1L); 

get()首先呼叫轉到DB加載Foo。當第二個調用被調用時,Hibernate將檢查在這個會話中是否已經檢索到ID爲1的任何Foo。如前所述,Hibernate將簡單地獲取該實例並返回給您。

但是,這種情況並不是最常見的情況,您將看到第一級緩存生效。試想一下:

// psuedo code only 
User user = findByUserName("ADRIAN"); // assume ID = 777 
List<User> users = findAllActiveUsers(); 

(假設上面的發現者在內部運行的查詢通Hibernate會話)當Hibernate運行查詢第二,內部休眠運行SQL,得到結果集,每條記錄轉換爲一個用戶。假設其中一個活動用戶具有ID 777.當Hibernate構造該User對象實例時,它將首先檢查它是否存在於第一級緩存中。因爲它先前被檢索過(在以前的查詢中可以通過用戶名找到),所以Hibernate不會構造一個新的User對象實例,而是簡單地重用先前構建的實例(並存儲在第一級緩存中)並將其用於結果列表中。通過這樣做,Hibernate可以確保在同一個會話中,如果您通過不同的方式檢索同一個實體(具有相同ID的同一個類),您可以始終假定該實體將是同一個對象實例。

想想一個更復雜的例子,您試圖從您的系統中檢索Order,這是指User(假設爲多對一)。你會發現什麼是不同的Order,只要它指的是相同的User(在DB中),它實際上指的是相同的User對象實例。


對於

的問題是在會話中可用如何,直到我關閉它

更休眠的內部實現細節。然而,從概念上講,你可以想象得到,每個會話內部都有一個Map,關鍵是實體類型+ ID,值是實體對象實例。

當您從數據庫中查詢和會話爲您構建實體時,對於每個實體,它將從地圖中查找是否已經存在。如果沒有,會話將構建實體並放入地圖。如果它已經存在,會議將只是利用實體在地圖

類似的想法時,你得到的ID實體(直通Session.get()Session.load()等)

0

你不需要需要從EntityManager中多次檢索同一個對象,但是如果你這樣做,你會得到同樣的對象。這就是緩存的意義。至於你的第二個問題:EntityManager保持對這個對象的引用,並且如果你再次請求同一個對象,則返回它。

我建議通過JPA教程,如http://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html。恕我直言,您應該專注於學習JPA並將Hibernate簡單地視爲JPA提供者。

0

如果存在該員工對象需要檢索做出後續調用,它可以從同一個會話中獲得,而不是從DB

0

這取決於你如何管理SessionEntityManager。如果它是根據請求創建的,則不需要再次查詢它。但是如果Session/EntityManager被重用,那麼可以多次檢索同一個對象,因此它將從第一級緩存中返回。