在學習Hibernate的過程中我們肯定會碰上一個名詞 緩存,一直都聽說緩存機制是Hibernate中的一個難點,它分為好幾種,有一級緩存,二級緩存和查詢緩存 今天呢,我就跟大家分享分享我所理解的一級緩存 要想完美的體現出緩存機制的話,我想通過查詢語句生成的sql應該就能夠很清楚的看到 那些Hibe ...
在學習Hibernate的過程中我們肯定會碰上一個名詞---緩存,一直都聽說緩存機制是Hibernate中的一個難點,它分為好幾種,有一級緩存,二級緩存和查詢緩存
今天呢,我就跟大家分享分享我所理解的一級緩存
要想完美的體現出緩存機制的話,我想通過查詢語句生成的sql應該就能夠很清楚的看到
那些Hibernate的配置信息我就不展示了,直接看關鍵代碼
場景:我要查詢同一個對象,查詢兩次,觀察在不同的情況下,sql語句的生成情況
我事先準備了一個HibernateUtil工具類,具體如下
package util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { //初始化一個ThreadLocal對象 private static final ThreadLocal sessionTL =new ThreadLocal(); private static Configuration configuration; private final static SessionFactory sessionFactory; static { try{ configuration=new Configuration().configure(); sessionFactory=configuration.buildSessionFactory(); }catch(Throwable ex){ ex.printStackTrace(); throw new ExceptionInInitializerError(ex); } } //獲取session public static Session currentSession(){ Session session=(Session)sessionTL.get(); if(session==null){ session=sessionFactory.openSession(); sessionTL.set(session); } return session; } //關閉session public static void closeSession(){ Session session= (Session)sessionTL.get(); sessionTL.set(null); session.close(); } }
正常我們訪問DB端時應該是訪問幾次就發送幾次sql,如下所示
//查詢學生信息 public static void select(){ //由班級查詢該班級學生信息 Session session=HibernateUtil.currentSession(); Grade grade=(Grade) session.get(Grade.class, 14); //輸出班級信息 System.out.println(grade.getGname()); Grade grade2=(Grade) session.get(Grade.class, 17); //輸出班級信息 System.out.println(grade2.getGname()); }
結果應該是這樣
那麼問題就來了,我們現在有如下幾個場景
場景一:使用同一個session連續查詢兩次同一個對象
//查詢學生信息 public static void select(){ //由班級查詢該班級學生信息 Session session=HibernateUtil.currentSession(); Grade grade=(Grade) session.get(Grade.class, 14); //輸出班級信息 System.out.println(grade.getGname()); Grade grade2=(Grade) session.get(Grade.class, 14); //輸出班級信息 System.out.println(grade2.getGname()); }
這個時候我們不難發現,此時我查詢的是同一個對象,按照正常理解,我查詢了兩遍應該向DB端發送兩條sql語句才對,下麵看看實際的sql數
這個時候可能有的小伙伴就有疑問了,我們後面再解釋這種情況,我們先接著看第二種場景
場景二:在第一次查詢完畢後,關閉session對象,重新開啟一個session然後繼續查詢同一個對象
//查詢學生信息 public static void select(){ //由班級查詢該班級學生信息 Session session=HibernateUtil.currentSession(); Grade grade=(Grade) session.get(Grade.class, 14); //輸出班級信息 System.out.println(grade.getGname()); //關閉session HibernateUtil.closeSession(); //重新獲取session session=HibernateUtil.currentSession(); Grade grade2=(Grade) session.get(Grade.class, 14); //輸出班級信息 System.out.println(grade2.getGname()); }
這個時候我們查詢的任然是同一個對象,結果卻如下圖
那麼,通過以上兩個場景的模擬,有些小伙伴可能已經明白是怎麼回事了,可能有些小伙伴們還有些迷糊,下麵我就講講我的看法吧~
總結:1:當我沒有關閉session時用的同一個session兩次訪問同一個對象時,只會向DB端發送一條sql語句
* 原因:因為我第一次訪問資料庫的時候Hibernate會自動的將我查詢出來的結果保留一份查詢出來的對象到一級緩存
並且這個額對象是根據OID唯一標識的,也可以理解為資料庫中的主鍵值,然後當我再一次訪問一個對象時,Hibernate
機制會自動的先去一級緩存中查找看有沒有OID與我要查詢的OID相同的對象,如果有的話,則直接從一級緩存中 拿數據
如果相同的OID則說明緩存中沒有我要的記錄,那麼就會直接去訪問DB端了,這樣的話,又會重新發送一條sql
2:當我第一次查詢完數據後立即關閉session,這時重新開啟一個session來訪問同一個對象,這時我們會發現它居然向資料庫發送了兩條Sql語句。這是為什麼呢?
* 原因:其實原因很簡單,因為我們雖然說是訪問的同一個對象,但是我們隨即就關閉了這個session而重新開啟了一個session,
此時我們訪問時的session是不一致的也就是說是兩個不同的session發出的請求,這樣理解的話,我們就不難理解了。
所以總結出,一級緩存是一個會話級別的緩存,當一次回話結束後該會話里的緩存則會全部的銷毀,所有我們自然就只能重新發送一條sql啦。