1. 程式人生 > >hibernate快取之【查詢快取】

hibernate快取之【查詢快取】

        說到hibernate中的快取我們瞭解的比較多的是一級和二級快取,通過前面兩篇部落格的總結我們知道一級和二級快取主要是快取查詢的實體或實體集的,那麼如果我們是通過HQL或SQL語句查詢普通的屬性,這種情況是否存在快取?答案是肯定的這種快取就是查詢快取。如果返回的是實體那麼查詢快取只會將實體的id快取下來。查詢快取的生命週期比較難以確定,官方的定義是“當關聯的表發生修改,查詢快取的生命週期結束”。自己對這句話不是特別理解。但是可以確定和session和sessionFactory都沒有關係。

        查詢快取的配置比價簡單,需要在hibernate.cfg.xml中配置

<propertyname="hibernate.cache.use_query_cache">true</property>

        在程式中需要使用session.setCacheable(true)進行顯示的呼叫開啟查詢快取,下面我們來看幾個例項,由於get和load是查詢實體的所以我們只測試list和iterate。

    /**
    * 開啟查詢,關閉二級快取,採用query.list()查詢普通屬性
    *
    * 在一個session中發query.list()查詢
    */
   public void testList1() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Listnames = session.createQuery("select s.namefrom Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0; i<names.size();i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         System.out.println("-------------------------------------------------------");
         //不會發出查詢語句,因為啟用查詢快取
         names= session.createQuery("select s.namefrom Student s")
                      .setCacheable(true)
                      .list();
         for (int i=0; i<names.size();i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exception e) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }

以上程式碼塊執行只發出一條查詢語句,可見開啟查詢快取對查詢普通屬性是有作用的。

   /**
    * 開啟查詢,關閉二級快取,採用query.list()查詢普通屬性
    *
    * 在兩個session中發query.list()查詢
    */
   public void testCache2() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Listnames = session.createQuery("select s.namefrom Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0; i<names.size();i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exception e) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         //不會發出查詢語句,因為查詢快取和session的生命週期沒有關係
         Listnames = session.createQuery("select s.namefrom Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0; i<names.size();i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exception e) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
   } <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

       以上程式碼塊是在兩個session中進行普通屬性的查詢,但是也只發出一條查詢語句,可見查詢快取的生命週期是有它的特殊性。

   /**
    * 開啟查詢,關閉二級快取,採用query.list()查詢實體
    *
    * 在兩個session中發query.list()查詢
    */
   public void testCache5() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Liststudents = session.createQuery("select s fromStudent s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
         session.getTransaction().commit();
      }catch(Exception e) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
        
            Liststudents = session.createQuery("select s fromStudent s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
      }catch(Exception e) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
   } 

        需要注意這個例項測試時需要在hib.cfg.xml中發二級快取關閉,我們發現執行的結果為第一次查詢發出一條語句查詢到所有的學生實體,但是第二次查詢時發出了N調語句,這是因為第一次返回結構後查詢快取將實體的id快取下來,第二次執行query.list(),將查詢快取中的id依次取出,分別到一級快取和二級快取中查詢相應的實體,如果快取中存在就使用快取中的實體物件,否則根據id發出查詢學生的語句。

小結:

        1、查詢快取快取普通屬性,如果返回的結果是實體則快取id

        2、在一級快取,二級快取和查詢快取都開啟的情況下作查詢操作時這樣的:查詢普通屬性,會先到查詢快取中取,如果沒有,則查詢資料庫;查詢實體,會先到查詢快取中取id,如果有,則根據id到快取(一級/二級)中取實體,如果快取中取不到實體,再查詢資料庫。