天天看點

hibernate5(6)操縱對象入門[1]Session緩存java對象在JVM中的存活條件hibernate的對象存活條件了解Session的緩存機制

在java中,我們使用<code>user user = new user();</code>來建立一個java對象時,jvm會為其配置設定一塊記憶體空間,此時,這個對象被變量“user”引用,那麼它就會一直存在于記憶體中,而如果我們我們的“引用者user”更新了,<code>user user = new vipuser()</code>。那麼原來<code>new user()</code>不再被任何變量引用,它就會結束自己的生命周期,然後會被jvm的智能垃圾回收期回收處理,以免再占用記憶體。

從以上分析,我們知道了java對象存活的條件就是:被(至少一個)變量引用

同樣的,假設在我們使用hibernate通路資料庫擷取了一個小a對象,這個小a一樣有它的存活條件,但與一般java對象不同,即使我們沒有建立任何變量來引用小a,我們的小a還是能夠活得好好的,這是因為小a被hibernate的session緩存下來了。

在session接口的實作類中,我們定義了一系列的java集合來存放從資料庫中擷取的資料,隻要我們的session執行個體沒有結束聲明周期,那麼存放其中的對象就不會結束其生命周期。

比如我們來看下面的例子

運作程式,觀察我們的列印資訊:

hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from t_user2 user0_ where user0_.id=? user1_1擷取完畢,耗時:26毫秒,準備開始擷取user1_2 user1_2擷取完畢,耗時:0毫秒,準備開始擷取user2 true false 在我們擷取user1_2時,并沒有查詢資料庫而且擷取時間幾乎為0,說明是直接從緩存中讀取的,而在比較對象屬性中,user1_1和user1_2相等,說明它們的引用位址也相同,而且必定與session緩存中的引用位址一緻 從上面我們還能看到,session辨別緩存的不同對象,是通過對象類型和對象辨別符id共同判别的,一旦兩者一緻,session即判别為同一對象,同時,我們也可歸納出利用session查詢資料庫的過程:比如我們要查詢id為1的user,則查詢過程如下時序圖所示:

created with raphaël 2.1.0sessionsessionsession緩存session緩存資料庫資料庫:1. 查找緩存是否有對象類型為user且id為12. 找到并傳回2. 沒找到則查詢資料庫3. 傳回資料結果并緩存4. 傳回資料到引用變量

在session清理緩存(flush)時,會進行髒檢查,如果發現緩存中的最新資料與資料庫記錄不一緻,會将最新資料更新到資料庫中。

那麼,session是如何進行髒檢查的呢?難道每次清理前,針對所有的緩存資料通路資料庫來進行匹對?這樣效率太低了。實際上,在上述時序圖的第3步到第4步之間,session會将獲得的資料結果先copy一份(這份copy還未經任何處理,肯定是和資料庫記錄一緻的),再傳回給引用變量。這樣我們将所有最新的資料與最初copy的校對一下,一旦出現差異,就将最新資料更新到資料庫。

在我們每次針對引用變量修改對象屬性後,對應的session緩存中的資料也會被修改,這是顯然的,因為它們的所指向的記憶體位址是一緻的。但修改後,hibernate并不會馬上執行相應的資料庫操作,隻有在特定條件下,如session被清理或特定的方法被調用才會通路資料庫。這裡談談session被清理的三個時間點:

1. 在完成事務送出之前,session會被清理一次。這樣的好處是一方面可以減少在事務作用過程中,大量執行的資料庫記錄修改操作。另一方面還可以盡可能縮短目前事務對相關資源的鎖定時間

2. 在執行一些複雜的查詢操作時,需要清理緩存,更新資料庫,確定查詢得到的資料是最新的。

3. 顯示地調用session.flush()方法

如果我們不希望在上述的某些時刻清理,我們可以通過session的setflushmode()方法來定制,它提供了3種模式共我們選擇:

模式

複雜查詢方法被執行

事務送出時

顯式調用flush()

使用場景

flushmode.auto(預設模式)

清理

正常應用場景

flushmode.commit

不清理

需要避免過多查詢操作清理緩存以提高性能的場景

flushmode.never

需要長時間運作的複雜事務場景

tips:從上面我們還能看出,我們要修改使用者資訊,完全用顯式地執行<code>session.update(user)</code>語句,隻需直接修改session緩存對象屬性即可,如下所示

我們資料庫中相應的user記錄name屬性也被修改了!

此外,session在清理緩存時,按照以下順序執行sql語句。

1。按照應用程式調用save()方法的先後順序,執行所有的對實體進行插入的insert語句。

2。所有對實體進行更新的update語句。

3。所有對實體進行删除的delete語句。

4。所有對集合元素進行删除、更新或插入的sql語句。

5。執行所有對集合進行插入的insert語句。

6。按照應用程式調用delete()方法的先後執行,執行所有對實體進行删除的delete語句。