1. 程式人生 > >Hibernate框架筆記04HQL_QBC查詢詳解_抓取策略優化機制

Hibernate框架筆記04HQL_QBC查詢詳解_抓取策略優化機制

新項目 long ini title 右外連接 int 方式 set 不包含

目錄

  • 1. Hibernate的查詢方式
    • 1.1 方式一:OID查詢
    • 1.2 方式二:對象導航查詢
    • 1.3 方式三:HQL方式
    • 1.4 方式四:QBC查詢
    • 1.5 方式五:SQL查詢
  • 2. 環境搭建
  • 3. HQL查詢
    • 3.1 簡單查詢
    • 3.2 別名查詢
    • 3.3 排序查詢
    • 3.4 條件查詢
    • 3.4 投影查詢
    • 3.5 分頁查詢
    • 3.6 分組統計查詢
    • 3.7 HQL的多表查詢
      • 3.7.1 SQL的多表查詢
      • 3.7.2 HQL的多表查詢
  • 4. QBC查詢
    • 4.1 簡單查詢
    • 4.2 排序查詢
    • 4.3 分頁查詢
    • 4.4 條件查詢
    • 4.5 統計查詢
    • 4.6 離線條件查詢(***)DetachedCriteria
  • 5. SQL查詢
  • 6. Hibernate的抓取策略
    • 6.1 延遲加載的概述
      • 6.1.1 什麽是延遲加載
      • 6.1.2 延遲加載的分類
    • 6.2 抓取策略
      • 6.2.1 抓取策略概述
      • 6.2.2 set上的fetch和lazy
      • 6.2.3 many-to-one上的fetch和lazy
      • 6.2.4 批量抓取

技術分享圖片

1. Hibernate的查詢方式

  • 在Hibernate中提供了5種查詢方式。

1.1 方式一:OID查詢

  • OID查詢:Hibernate根據對象的OID(主鍵)進行檢索。
  • 使用get()方法
    • Customer customer = session.get(Customer.class,1L);
  • 使用load()方法
    • Customer customer = session.load(Custoemr.class,1L);

1.2 方式二:對象導航查詢

  • 對象導航檢索:Hibernate根據一個已經查詢到的對象,獲得其關聯的對象的一種查詢方式。

    LinkMan linkMan = session.get(LinkMan.class,1L);
    Customer customer = linkMan.getCustomer();
    
    Customer customer = session.get(Customer.class,2L);
    Set<LinkMan> linkMans = customer.getLinkMans();

1.3 方式三:HQL方式

  • HQL查詢Hibernate Query Language,Hibernate的查詢語言,是一種面向對象的方式的查詢語言,語法類似SQL。通過session.createQuery(),接收一個HQL進行查詢方式。

1.4 方式四:QBC查詢

  • QBC查詢Query By Criteria,條件查詢。是一種更加面向對象化的查詢方式。

1.5 方式五:SQL查詢

  • SQL查詢:通過使用SQL語句進行查詢。

2. 環境搭建

  • 創建一個新項目,導入相關jar包

  • 新建數據庫,新建數據表,分別為cst_custoemr和cst_linkman

  • 新建兩個實體,分別為Customer和LinkMan
    • Customer中生成toString方法,不包含LinkMan
    • LinkMan中生成toString方法,不包含Customer
  • 準備工具類,配置文件,映射文件

  • 生成測試的數據,該方法執行3次

    /**
     *    HQL的查詢方式的測試類
     * @author itzhouq
     *
     */
    public class HibernateDemo1 {
    
      @Test
      public void test1() {
          Session session = HibernateUtils.getCurrentSession();
          Transaction transaction = session.beginTransaction();
          Customer customer = new Customer();
          customer.setCust_name("莫爾德");
          for (int i = 0; i < 10; i++) {
              LinkMan linkMan = new LinkMan();
              linkMan.setLkm_name("老馬"+i);
    
              customer.getLinkMans().add(linkMan);
    
              session.save(linkMan);
          }
          session.save(customer);
          transaction.commit();
    
      }
    }

3. HQL查詢

3.1 簡單查詢

@Test
    public void test2() {//HQL的簡單查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 簡單查詢
        Query query = session.createQuery("from Customer");
        List<Customer> list = query.list();
        
        // sql中支持*號的寫法:select * from cst_customer;但是在HQL中不支持*號的寫法。
//      Query query2 = session.createQuery("select * from from Customer");// 報錯
//      List<Customer> list2 = query.list();
        
        for (Customer customer : list) {
            System.out.println(customer);
            
        }
        transaction.commit();
    }

3.2 別名查詢

@Test
    public void test3() {// 別名查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 別名查詢
//      Query query = session.createQuery("from Customer c");
//      List<Customer> list = query.list();
        
        Query query = session.createQuery("select c from Customer c");
        List<Customer> list = query.list();
        
        for (Customer customer : list) {
            System.out.println(customer);
            
        }
        transaction.commit();
    }

3.3 排序查詢

@Test
    public void test5() {// 排序查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 排序查詢
        // 默認情況
        //List<Customer> list = session.createQuery("from Customer order by cust_id").list();
        
        // 設置兼降序排序       升序使用asc 降序使用desc
        List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
        
        
        
        for (Customer customer : list) {
            System.out.println(customer);
            
        }
        transaction.commit();
    }

3.4 條件查詢

@Test
    public void test4() {// 排序查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 排序查詢
        // 1. 按位置綁定:根據參數的位置進行綁定
        // 一個條件
//      Query query = session.createQuery("from Customer where cust_name = ?");
//      query.setParameter(0, "朱元璋");
        
        // 多個條件
//      Query query = session.createQuery("from Customer where cust_source = ? and cust_name like ?");
//      query.setParameter(0, "朋友推薦");
//      query.setParameter(1, "朱%");
        
        // 2. 按名稱綁定
        Query query = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
        // 設置參數:
        query.setParameter("aaa", "朋友推薦");
        query.setParameter("bbb", "朱%");
        List<Customer> list = query.list();
        
        for (Customer customer : list) {
            System.out.println(customer);
            
        }
        transaction.commit();
    }

3.4 投影查詢

  • 投影查詢:查詢對象的某個或某些屬性
@Test
    public void test6() {// 投影查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 投影查詢
        // 單個屬性
//      List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
//      for (Object customer : list) {
//          System.out.println(customer);
//          
//      }
        
        // 多個屬性:
//      List<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();
//      for (Object[] objects : list) {
//          System.out.println(Arrays.toString(objects));
//      }
        
        // 查詢多個屬性,但我想封裝到對象中-----需要這兩個參數的構造函數
        List<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();
        for (Object[] customer : list) {
            System.out.println(Arrays.toString(customer));
        }
        
        transaction.commit();
    }

3.5 分頁查詢

@Test
    public void test7() {// 分頁查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 分頁查詢
        Query query = session.createQuery("from LinkMan");
        query.setFirstResult(20);
        query.setMaxResults(5);
        List<LinkMan> list = query.list();
        for (LinkMan linkMan : list) {
            System.out.println(linkMan);
        }
        
        transaction.commit();
    }

3.6 分組統計查詢

@Test
    public void test8() {// 分組統計查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 分組統計查詢
        Object object = session.createQuery("select count(*) from Customer").uniqueResult();
        System.out.println(object);
        
        //分組統計:
        Query query = session.createQuery("select cust_source,count(*) from Customer group by cust_source");
        List<Object[]> list = query.list();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
        transaction.commit();
    }

3.7 HQL的多表查詢

3.7.1 SQL的多表查詢

  • 連接查詢
    • 交叉連接:笛卡爾積
    • 內連接:innner join(inner可以省略)
      • 隱式內連接:select * from A,B where A.id = B.aid;
      • 顯式內連接:select * from A inner join B on A.id = B.aid;
    • 外連接:outer可以省略
      • 左外連接:select * from A left outer join B on A.id = B.id;
      • 右外連接:select * from A right outerjoin B on A.id = B.id;
  • 子查詢

3.7.2 HQL的多表查詢

  • 連接查詢
    • 交叉連接
    • 內連接:
      • 顯式內連接
      • 隱式內連接
      • 迫切內連接
    • 外連接:
      • 左外連接
      • 右外連接
      • 迫切左外連接
@Test
    public void test7() { // 多表查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        // SQL:select * from cst_customer c inner join cst_linkman l on c.cust_id = l.lkm_cust_id
        // HQL:內連接from Customer c inner join c.linkMans
        // 內連接得到的是一個數組
        
//      List<Object[]> list = session.createQuery("from Customer c inner join c.linkMans").list();
//      for (Object[] objects : list) {
//          System.out.println(Arrays.toString(objects));
//      }
        
        // HQL:迫切內連接,其實就是在普通的內連接inner join後添加一個關鍵字fetch.
        // 迫切內連接的到的是一個對象,在Customer的toString中給定LinkMans可以得到全部字段
        List<Customer> list2 = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans").list();
        for (Customer customer : list2) {
            System.out.println(customer);
        }
        
        transaction.commit();
    }

4. QBC查詢

4.1 簡單查詢

@Test
    public void test1() { // 簡單查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //獲得Criteria的對象
        Criteria criteria = session.createCriteria(Customer.class);
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        
        transaction.commit();
    }

4.2 排序查詢

@Test
    public void test2() { // 排序查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //獲得Criteria的對象
        Criteria criteria = session.createCriteria(Customer.class);
//      criteria.addOrder(Order.desc("cust_id"));   // 降序
        criteria.addOrder(Order.asc("cust_id"));    // 升序
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        
        transaction.commit();
    }

4.3 分頁查詢

@Test
    public void test3() { // 分頁查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //獲得Criteria的對象
        Criteria criteria = session.createCriteria(LinkMan.class);
        criteria.setFirstResult(20);
        criteria.setMaxResults(5);
        
        List<LinkMan> list = criteria.list();
        for (LinkMan linkMan : list) {
            System.out.println(linkMan);
        }
        
        transaction.commit();
    }

4.4 條件查詢

@Test
    public void test4() { // 條件查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //獲得Criteria的對象
        Criteria criteria = session.createCriteria(Customer.class);
        // 設置條件
        /*
         *  =       eq
         *  >       gt
         *  >=      ge
         *  <       lt
         *  <=      le
         *  <>      ne
         *  like
         *  in
         *  and
         *  or
         */
        criteria.add(Restrictions.eq("cust_source", "小廣告"));
        criteria.add(Restrictions.like("cust_name", "李%"));
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        
        transaction.commit();
    }

4.5 統計查詢

@Test
    public void test5() { // 條件查詢
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //獲得Criteria的對象
        Criteria criteria = session.createCriteria(Customer.class);
        /**
         *  add     :普通的條件。where後面條件
         *  addOrder:排序
         *  setProjecttion:聚合函數和group by having
         */
        
        criteria.setProjection(Projections.rowCount());
        Long num = (Long) criteria.uniqueResult();
        System.out.println(num);
        
        transaction.commit();
    }

4.6 離線條件查詢(***)DetachedCriteria

  • 離線條件查詢在前臺需要傳遞多個條件,用於篩選的時候很方便,可以不用在dao層拼接字符串

    技術分享圖片

  • 代碼

@Test
    public void test6() { // 離線條件查詢
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
        detachedCriteria.add(Restrictions.like("cust_name", "李%"));
        
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Criteria criteria = detachedCriteria.getExecutableCriteria(session);
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        
        transaction.commit();
    }

5. SQL查詢


    @Test
    public void test1() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        // 調用的createSQLQuery,返回的值遍歷後是數組形式的集合
//      SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
//      List<Object[]> list = sqlQuery.list();
//      for (Object[] objects : list) {
//          System.out.println(Arrays.toString(objects));
//      }
        
        SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
        sqlQuery.addEntity(Customer.class); //封裝到實體Customer中
        List<Customer> list = sqlQuery.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        
        transaction.commit();
    }

6. Hibernate的抓取策略

6.1 延遲加載的概述

6.1.1 什麽是延遲加載

  • 延遲加載:lazy(懶加載)。執行到該行代碼的時候,不會發送語句去進行查詢,在真正使用這個對象的屬性的時候才會發送SQL語句進行查詢。

6.1.2 延遲加載的分類

  • 類級別的延遲加載

    • 指的是通過load方法查詢某個對象的時候,是否采用延遲加載。session.load(Customer.class,1L);
    • 類級別的延遲加載通過<class>上的lazy進行配置。讓lazy失效的方法有:
      • 將lazy設置為false
      • 將持久化類使用final修改
      • Hibernate.ininialize()
  • 關聯級別的延遲加載

    • 指的是在查詢到某個對象的時候,查詢其關聯對象的時候,是否采用延遲加載。

      Customer customer = session.get(Customer.class,1L);
      customer.getLinkMans();
      //通過客戶獲得聯系人的時候,聯系人對象是否采用了延遲記載,稱為關聯級別的延遲加載。
    • 抓取策略往往會和關聯級別的延遲加載一起使用,優化語句。

6.2 抓取策略

Customer.hbm.xml

<set name="linkMans" fetch="select" lazy="true">
    <!-- column多的一方的外鍵的名稱 -->
    <key column="lkm_cust_id"></key>
    <!-- class:多的一方的類的全限定名 -->
    <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
</set>

6.2.1 抓取策略概述

  • 通過一個對象抓取到關聯對象需要發送SQL語句,SQL語句如何發送,發送成什麽樣格式?這些可以通過策略進行配置。
    • 通過<set>或者<many-to-one>上的fetch屬性進行配置
    • fetch和這些標簽上的lazy如何設置,優化發送的SQL語句。

6.2.2 set上的fetch和lazy

  • fetch:抓取策略,控制SQL語句格式
    • select:默認值,發送普通的select語句,查詢關聯對象
    • join:發送一條迫切左外連接查詢關聯對象。
    • subeselect:發送一條子查詢查詢其關聯對象。
  • lazy:延遲加載,控制查詢關聯對象的時候是否采用延遲加載
    • true:默認值,查詢關聯對象的時候,采用延遲加載
    • false:查詢關聯對象的時候,不采用延遲加載
    • extra:及其懶惰。
  • 實際開發過程中,一般采用默認值。如果有特殊需求,可能需要配置join。

6.2.3 many-to-one上的fetch和lazy

  • fetch:抓取策略,控制SQL語句格式
    • select:默認值,發送普通的select語句,查詢關聯對象。
    • join:發送一條迫切左外連接
  • lazy:延遲加載,控制查詢關聯對象的時候是否采用延遲加載
    • proxy:默認值,proxy具體的取值,取決於另一端的class上的lazy的值。
    • false:查詢關聯對象,不采用延遲。
    • no-proxy:不用
  • 在實際開發過程中,一般采用默認值。如果有特殊的需求,可能需要配置join。

6.2.4 批量抓取

  • 一批關聯對象一起抓取,betch-size。

    package com.itzhouq.hibernate.demo;
    
    import java.util.List;
    
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    import org.junit.Test;
    
    import com.itzhouq.hibernate.domain.Customer;
    import com.itzhouq.hibernate.domain.LinkMan;
    import com.itzhouq.hibernate.utils.HibernateUtils;
    
    /*
     *    批量抓取測試
     */
    public class HibernateDemo4 {
    
    
      @Test
      public void test1() {
          // 獲取客戶的時候,批量抓取聯系人
          // 在Customer.hbm.xml中set上配置batch-size
          Session session = HibernateUtils.getCurrentSession();
          Transaction transaction = session.beginTransaction();
          List<Customer> list = session.createQuery("from Customer").list();
          for (Customer customer : list) {
              System.out.println(customer.getCust_name());
              for (LinkMan linkMan : customer.getLinkMans()) {
                  System.out.println(linkMan.getLkm_name());
              }
          }
    
          transaction.commit();
      }
    }
    <set name="linkMans" batch-size="5">
        <!-- column多的一方的外鍵的名稱 -->
        <key column="lkm_cust_id"></key>
        <!-- class:多的一方的類的全限定名 -->
        <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
    </set>

Hibernate框架筆記04HQL_QBC查詢詳解_抓取策略優化機制