4.Hibernate查詢方式詳解

一、Hibernate的查詢方式

在Hibernate中共提供了5種查詢方式:OID查詢、對象導航檢索、HQL檢索、QBC檢索、SQL檢索

1.OID查詢

概述:Hibernate根據對象的OID(主鍵)進行檢索,有兩種方法get和load。
使用get方法

Customer customer = session.get(Customer.class,1l);

使用load方法

Customer customer = session.load(Customer.class,1l);

2.對象導航檢索

概述:Hibernate根據一個已經查詢到的對象,獲取其關聯的對象的一種方式。
舉例

Linkman linkman = session.get(Linkman.class.1l);  //通過聯繫人來查用戶
Customer customer = linkman.getCustomer();

Customer customer= session.get(Customer.class.1l);  //通過聯繫人來查用戶
Set<Linkman> linkmans = customer.getLinkmans();

3.HQL檢索

(1) 搭建hibernate環境

參考:Hibernate項目創建

(2) 初始化數據

注:此處省略實體類、配置文件等創建。
代碼

	@Test
    public void demo1() {
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	//創建兩個客戶
    	Customer customer1 = new Customer();
    	customer1.setCust_name("張三丰");
    	Customer customer2 = new Customer();
    	customer2.setCust_name("張無忌");
    	
    	//設置關係 	
    	for(int i=0; i < 10; i++) { 
    		Linkman linkman1 = new Linkman();
    		linkman1.setLkm_name("郭襄"+i);
    		linkman1.setCustomer(customer1);
    		customer1.getLinkmans().add(linkman1);
    		
    		session.save(linkman1);
    	}
    	 	
    	for(int i=0; i < 10; i++) {
    		Linkman linkman2 = new Linkman();
    		linkman2.setLkm_name("趙敏"+i);
    		linkman2.setCustomer(customer2);
    		customer2.getLinkmans().add(linkman2);
    		
    		session.save(linkman2);
    	}
      	
    	//保存數據
    	session.save(customer1);
    	session.save(customer2);
    	   	
    	tx.commit();    	
    }

初始化結果:
在這裏插入圖片描述

(3) HQL簡單查詢和別名查詢

簡單查詢
代碼:

	@Test
    public void demo2() {
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	//簡單查詢
    	Query query = session.createQuery("from Customer");
    	List<Customer> list = query.list();
    	
    	for(Customer customer : list) {
    		System.out.println(customer);
    	}
   	   	
    	tx.commit();    	
    }

查詢結果:
在這裏插入圖片描述
注意:SQL中支持“select * from cst_customer”方式的 的查詢,但是HQL中不支持號的寫法,另外,這裏的Customer是指的是Customer類,而不是表。

別名查詢:???回頭再看看
代碼:

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

(4) 排序查詢和條件查詢

排序查詢
代碼:

	@Test
    public void demo4() {  //排序查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	//升序查詢,另外,默認也爲升序查詢
    	//List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
    	
    	//降序查詢
    	List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
    	 	
    	for(Customer customer : list) {
    		System.out.println(customer);
    	}
   	   	
    	tx.commit();    	
    }

查詢結果:
在這裏插入圖片描述
條件查詢
一、按位置綁定:
注:這裏的setParameter(a,b);中的a = 0代表語句中第一個參數,a = 1 代表語句中的第二個參數,b代表參數的限定值,也就是說這裏的a代表該參數在HQL語句中的位置。

	@Test
    public void demo5() {  //條件查詢,按位置綁定
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	//按位置綁定
    	Query query = session.createQuery("from Customer where cust_source = ? and cust_name like ?");
    	query.setParameter(0, "今日頭條");
    	query.setParameter(1, "%無忌");
    	List<Customer> list = query.list();
    	
    	 	
    	for(Customer customer : list) {
    		System.out.println(customer);
    	}
   	   	
    	tx.commit();    	
    }

在這裏插入圖片描述
二、按名稱綁定
代碼:

	@Test
    public void demo5() {  //條件查詢,按名稱綁定
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	//按位置綁定
    	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);
    	}
   	   	
    	tx.commit();    	
    }

注:測試結果與一、按位置綁定相同。

(5) 投影查詢和分頁查詢

投影查詢:查詢對象的一個和一些屬性。
一個屬性:

	@Test
    public void demo6() {  //投影查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
    	for(Object object : list) {
    		System.out.println(object);
    	}
   	   	
    	tx.commit();    	
    }

在這裏插入圖片描述
多個屬性:

	@Test
    public void demo6() {  //投影查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	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));
    	}
   	   	
    	tx.commit();    	
    }

在這裏插入圖片描述
多個屬性封裝到對象中:
概述:將要查詢的屬性(這裏以兩個舉例)封裝到一個對象中(提前在相應類中創建這兩個屬性的構造方法),然後查詢得到對象列表,並打印。注:在創建其他構造方法時,需要加上一個無參的構造方法,因爲這時已經不只是有默認的構造方法了。

	@Test
    public void demo6() {  //投影查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
    	for(Customer customer : list) {
    		System.out.println(customer);
    	}
   	   	
    	tx.commit();    	
    }

在這裏插入圖片描述
分頁查詢

	@Test
    public void demo7() {  //分頁查詢,這裏只分頁查詢一頁
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	Query query = session.createQuery("from Linkman");
    	query.setFirstResult(0);   //分頁開始的位置
    	query.setMaxResults(5);    //查詢一頁的最大的個數
    	List<Linkman> list = query.list();
    	for(Linkman linkman : list) {
    		System.out.println(linkman);
    	}
   	   	
    	tx.commit();    	
    }

在這裏插入圖片描述

(6) 分組統計查詢

概述:這裏的統計查詢包括:簡單統計查詢(單純地統計數目)和分組統計查詢(根據特定屬性統計數目)

	@Test
    public void demo8() {  //統計查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	//簡單統計,聚合函數的使用,聚合函數包括:count()、max()、min()、avg()、sum()
    	Object object = session.createQuery("select count(*) from Customer").uniqueResult();
    	System.out.println(object);
    	
    	//分組統計:
    	List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source ").list();
    	for(Object[] objects: list) {
    		System.out.println(Arrays.toString(objects));
    	}

    	tx.commit();    	
    }

在這裏插入圖片描述
篩選:另外,在分組統計查詢中篩選出統計數目大於等於2的數據,修改代碼如下:

List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source having count(*) >=2").list();

在這裏插入圖片描述

4.QBC檢索

概述:QBC(Query By Criteria),條件查詢,是一種更加面向對象化的查詢方式。

(1) 簡單查詢與排序查詢

簡單查詢

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

在這裏插入圖片描述

排序查詢
升序:asc
降序:desc

	@Test
    public void demo2() {  //排序查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.addOrder(Order.desc("cust_id"));
        List<Customer> list = criteria.list();
        
        for(Customer customer : list) {
        	System.out.println(customer);
        }
        
    	tx.commit();    	
    }

在這裏插入圖片描述

(2) 分頁查詢和條件查詢

分頁查詢

	@Test
    public void demo4() {  //分頁查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        Criteria criteria = session.createCriteria(Linkman.class);
        criteria.setFirstResult(0);
        criteria.setMaxResults(5);
        List<Linkman> list = criteria.list();
        
        for(Linkman linkman : list) {
        	System.out.println(linkman);
        }
        
    	tx.commit();    	
    }

在這裏插入圖片描述

條件查詢

	@Test
    public void demo3() {  //條件查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        Criteria criteria = session.createCriteria(Customer.class);
        //設置條件
        /*
         * =    eq
         * >    gt
         * >=   ge
         * <    lt
         * <=   le
         * !=   ne
         * like
         * in
         * and  :QBC默認爲and
         * or   :也可以使用or,即或的關係
         * */
        criteria.add(Restrictions.eq("cust_source", "今日頭條"));
        criteria.add(Restrictions.like("cust_name", "張%"));
        //使用or代碼舉例:criteria.add(Restrictions.or(Restrictions.like("cust_name", "張%")));
        List<Customer> list = criteria.list();
        
        for(Customer customer : list) {
        	System.out.println(customer);
        }
        
    	tx.commit();    	
    }

在這裏插入圖片描述

(3) 統計查詢

	@Test
    public void demo5() {  //統計查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        Criteria criteria = session.createCriteria(Linkman.class);
        /*
         * add            :普通的條件,一般是where的方式
         * addOrder       :p排序
         * setProjection  :聚合函數和group by having
         * */
        criteria.setProjection(Projections.rowCount());
        Long sum = (Long) criteria.uniqueResult();
        System.out.println(sum);
        
    	tx.commit();    	
    }

在這裏插入圖片描述

(4) QBC離線條件查詢

概述:使用DetachedCriteria,離線也即脫離Session使用,在後期SSH整合時會有顯著效果。待補充。。。。。。

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

5.SQL檢索

簡單查詢

	@Test
    public void demo9() {  //SQL 方式簡單查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
    	/*
    	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);
        List<Customer> list = sqlQuery.list();
        for(Customer customer : list ) {
        	System.out.println(customer);
        }
       
    	tx.commit();    	
    }

在這裏插入圖片描述
在這裏插入圖片描述

6.HQL多表查詢

(1) SQL多表查詢回顧:

連接查詢
  交叉連接:笛卡爾積,select * from list_A,list_B; 查詢兩個表所有交叉相乘的數據;
  內連接:inner join (其中inner可以省略),查詢兩個表所有有關聯的數據;
    隱式內連接:select * from list_A,list_B where list_A.id = list_B.aid;
    顯示內連接:select * from list_A inner jion list_B on list_A.id = list_B.aid;
  外連接:
    左外連接:left outer join (outer 可以省略),查詢左邊表與右邊表的關聯信息和左邊表的其餘信息;
    select * from list_A left outer join list_B on list_A.id = list_B.aid;
    右外連接:right outer join (outer 可以省略),查詢右邊表與左邊表的關聯信息和右邊表的其餘信息;
    select * from list_A right outer join list_B on list_A.id = list_B.aid;

(2) HQL多表查詢:

連接查詢
  交叉連接:
  內連接:
    隱式內連接:
    顯式內連接:
    迫切內連接:
  外連接:
    左外連接:
    右外連接:
    迫切左外連接:

(3) 舉例:

普通內連接:查詢出兩個表所有關聯的數據,這裏將查詢結果保存在對象數組中,對象數組中的每一條數據都由Customer對象和其對應的Linkman對象組成。

	@Test
    public void demo7() {  //普通內查詢
        //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
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        List<Object[]> list = session.createQuery("from Customer c inner join c.linkmans").list();
        for(Object[] objects : list ) {
        	System.out.println(Arrays.toString(objects));
        }
        
    	tx.commit();    	
    }

在這裏插入圖片描述
在這裏插入圖片描述

迫切內連接:首先在Customer類中toString方法中加上linkmans集合的打印,這裏查詢到的信息直接封裝到Customer對象中(因爲Customer對象中包含Linkman類型的集合,可以打印Linkman的信息),這就是迫切內連接查詢。
在這裏插入圖片描述
fetch是“迫切”的標記,select distinct c 的功能是去掉查詢到的重複數據項:

	@Test
    public void demo8() {  //迫切內連接查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkmans").list();
        for(Customer customer : list ) {
        	System.out.println(customer);
        }
        
    	tx.commit();    	
    }

在這裏插入圖片描述

二、Hibernate的抓取策略

1.延遲加載

(1) 什麼是延遲加載?

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

(2) 延遲加載的分類?

類級別的延遲加載
  指的是通過load方法查詢某個對象的時候,是否採用延遲加載,session.load(Customer.class,1l);
  類級別的延遲加載通過相應類映射配置文件中的標籤上的lazy進行配置,默認lazy = “true”,使得lazy失效的方法:
  (1)將lazy設置爲false;
  (2)將持久化類使用final修飾;
  (3)使用Hibernate.Initialize();
關聯級別的延遲加載
  指的是在查詢到某個對象的時候,查詢其關聯的對象的時候,是否採用延遲加載,一般在相應配置文件中的set、many-to-one標籤設置lazy;
  如:Customer customer = session.get(Customer.class,1l);
  customer.getLinkmans(); //這時,通過客戶獲取聯繫人的時候,看是否採用了延遲加載,稱爲關聯級別的延遲。

2.抓取策略

(1) 抓取策略的概述

概述:通過一個對象抓取到關聯對象需要發送SQL語句,SQL語句如何發送,發送成什麼樣的格式通過策略進行配置:
  通過 或 上通過fetch屬性進行設置;
  fetch和這些標籤上的lazy如何設置來優化發送SQL語句。

(2) < set >上的fetch和lazy

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

舉例
1.fetch = “select” lazy = “true” :都爲默認值,這時,會查詢關聯對象,並且對關聯對象進行延遲查詢,
在這裏插入圖片描述

	@Test
    public void demo1() {  //SQL 方式簡單查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        //查詢1號客戶
    	Customer customer = session.get(Customer.class, 1l);   //第一行
    	System.out.println(customer.getCust_name());    //第二行
    	
    	//查詢1號客戶每個聯繫人的信息
    	for(Linkman linkman : customer.getLinkmans()) {   //第三行
    		System.out.println(linkman.getLkm_name());    //第四行
    	}
       
    	tx.commit();    	
    }

測試結果:在執行第一行代碼時,在查詢Customer對應表中第一行數據的時候,會級聯查詢與Customer對象關聯的Linkman對象,但由於這裏級聯懶查詢,所以暫時不發送SQL語句,等待執行第三行代碼時,這時使用Customer對象級聯的Linkman對象了,這時會發送級聯對象的SQL語句。
在這裏插入圖片描述
在這裏插入圖片描述
2.fetch = “select” lazy = “false” :這時,會查詢關聯對象,對關聯對象不進行延遲查詢,即直接發送查詢級聯對象的SQL語句,
在這裏插入圖片描述
3.fetch = “select” lazy = “extra” :這時,會查詢關聯對象,對關聯對象進行極其懶查詢,即僅在使用級聯對象內容的時候才發送SQL語句,對級聯對象進行查詢、統計等操作時也不發送SQL語句。

	@Test
    public void demo1() {  //SQL 方式簡單查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        //查詢1號客戶
    	Customer customer = session.get(Customer.class, 1l);
    	System.out.println(customer.getCust_name());
    	System.out.println(customer.getLinkmans().size());
    	tx.commit();    	
    }

“極其懶”查詢結果:
在這裏插入圖片描述
懶查詢結果:
在這裏插入圖片描述
4.fetch = “join” lazy = “true” :這時,發送迫切左外連接(左外連接:查詢左邊表與右邊表的關聯信息和左邊表的其餘信息)SQL語句,這時查左表的同時,也查詢了右表,所以這裏不存在延遲查詢,也就是說lazy標籤失效。

	@Test
    public void demo1() {  //迫切左外連接查詢
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        //查詢1號客戶
    	Customer customer = session.get(Customer.class, 1l);
    	System.out.println(customer.getCust_name());
    	System.out.println(customer.getLinkmans().size());
    	tx.commit();    	
    }

這時,只發送一條同時查詢左右兩張表的SQL語句:
在這裏插入圖片描述

(3) < many-to-one >上的fetch和lazy

fetch:抓取策略,控制SQL語句格式:
  select:默認值,發送普通的select語句,查詢關聯對象;
  join:發送一條迫切左外連接,查詢關聯對象;
lazy:延遲加載,控制查詢關聯對象的時候是否採用延遲:
  proxy:默認值,proxy的取值取決於“一”的一方中中的< set >上lazy值,該lazy值爲true則proxy代表true,若該lazy值爲false,則proxy也爲false;
  false:查詢關聯對象的時候,不使用延遲加載;
  no-proxy:極少使用;
注:在實際開發中,一般都採用默認值,如果有特殊的需要,可能需要配置join。

(4) 批量抓取

概述:在抓取客戶的時候,批量抓取聯繫人,比如:現在要抓取5個客戶,同時要抓取每個客戶的聯繫人,對應於每個客戶,都要重新抓取該客戶對應的聯繫人,也就是說此時一共要發送6條SQL語句(抓取客戶1條+分別抓取客戶對應的聯繫人5條),因爲這裏< set >中的batch-size屬性默認爲1,即一次批量抓取一個聯繫人,如果將其設置爲5,則一次批量抓取5個聯繫人,這時只需要發送2條SQL語句即可。

數據庫
客戶表:
在這裏插入圖片描述
聯繫人表:
在這裏插入圖片描述
查詢客戶來批量抓取聯繫人信息
在這裏插入圖片描述

	@Test
    public void demo2() {  //批量抓取
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = 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());
        	}	
        }
    	tx.commit();    	
    }

分析:通過查詢客戶,來批量抓取客戶相關聯的聯繫人信息,對於這種方式,需要在客戶配置文件Customer.hbn.xml中的< set >標籤中設置batch-size,此時只有兩個客戶關聯了聯繫人,批量查詢設置的值爲4,所以除了查詢客戶發送的一條SQL語句外,發送一條SQL語句就可以。
查詢聯繫人來批量抓取客戶信息
在這裏插入圖片描述

	@Test
    public void demo3() {  //批量抓取
    	Session session = HibernateUtils.getCurrentSession();
    	Transaction tx = session.beginTransaction();
    	
        List<Linkman> list = session.createQuery("from Linkman").list();
        for(Linkman linkman : list) {
        	System.out.println(linkman.getLkm_name());
        	System.out.println(linkman.getCustomer().getCust_name());
        	
        }
    	tx.commit();    	
    }

分析:通過查詢聯繫人,來批量抓取聯繫人相關聯的客戶信息,對於這種方式,需要在客戶配置文件Customer.hbn.xml中的< class >標籤中設置batch-size,此時這裏20個聯繫人,但是與其關聯的客戶只有2個,批量查詢設置的值爲4,所以除了查詢聯繫人發送的一條SQL語句外,發送一條SQL語句就可以。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章