1. 程式人生 > >Hibernate hql總結及BaseDao封裝

Hibernate hql總結及BaseDao封裝

1.hql:Hibernate Query Language(Hibernate查詢語言)

作用:方便進行資料庫操作

2. hql和sql區別

     1.hql是基於實體屬性進行查詢的;sql是基於表實體進行查詢的

     2.hql區分大小寫,關鍵字不區分大小寫;sql不區分大小寫

     3.hql是面向物件的查詢語言;sql是面向結構的查詢語言

     4.hql佔位符下標從0開始(目前推薦使用:命名引數);sql佔位符下標從1開始

3.5種處理hql查詢返回的結果集

這裡以Book類為例項

        /**
	 * 結果處理一:當結果集為集合,查單個也可以通過這種方式,只不過不需要遍歷
	 */
	@Test
	public void testList1() {
		String hql = "from Book";
		Query query = session.createQuery(hql);
		List<Book> list = query.list();
		for (Book book : list) {
			System.out.println(book);
		}
	}
	
	/**
	 * 結果處理二:當結果集為集合,並且只查詢其中一列時
	 */
	@Test
	public void testList2() {
		String hql = "select bookName from Book";
		Query query = session.createQuery(hql);
		List<String> list = query.list();
		for (String bname : list) {
			System.out.println(bname);
		}
	}
	
	/**
	 * 結果處理三:當結果集為集合,並且查詢兩列及兩列以上,使用Object[]
	 */
	@Test
	public void testList3() {
		String hql = "select bookId,bookName from Book";
		Query query = session.createQuery(hql);
		List<Object[]> list = query.list();
		for (Object[] book : list) {
			System.out.println(Arrays.toString(book));
		}
	}
	
	/**
	 * 結果處理四:當結果集為集合,並且查詢兩列及兩列以上,使用hibernate內建函式
	 */
	@Test
	public void testList4() {
		String hql = "select new map(bookId,bookName) from Book";
		Query query = session.createQuery(hql);
		List<Map> list = query.list();
		for (Map book : list) {
			System.out.println(book);
		}
	}
	
	/**
	 * 結果處理五:當結果集為集合,並且查詢兩列及兩列以上,使用構造方法進行結果處理,記得提供對應構造器!!
	 */
	@Test
	public void testList5() {
		String hql = "select new Book(bookId,bookName) from Book";
		Query query = session.createQuery(hql);
		List<Book> list = query.list();
		for (Book book : list) {
			System.out.println(book);
		}
	}

4.hql的命名引數:等同於佔位符,推薦使用該方式

        @Test
	public void testList6() {
		//此處的:bookIds相當於佔位符,不要漏掉:
		String hql = "from Book where bookId in (:bookIds)";
		Query query = session.createQuery(hql);
		List<Integer> params = new ArrayList<Integer>();
		params.add(1);
		params.add(2);
		//為bookIds賦值,也可以使用下標,hql的下標是從0開始
		query.setParameterList("bookIds",params);
		List<Book> list = query.list();
		for (Book book : list) {
			System.out.println(book);
		}
	}

5.使用hql完成聯表查詢

        @Test
	public void testList7() {
		String hql = "select o.order_no,oi.product_id from Order o,OrderItem oi where o.order_id = oi.order.order_id";
		//String hql = "select o.order_no,oi.product_id from Order o,OrderItem oi where o = oi.order";
		Query query = session.createQuery(hql);
		List<Object[]> list = query.list();
		for (Object[] obj : list) {
			System.out.println(Arrays.toString(obj));
		}
	}

6.hql的聚合函式

   sum    avg    max    min    count

這裡以count示例

        @Test
	public void testList8() {
		String hql = "select count(*) from Book";
		Query query = session.createQuery(hql);
		Object obj = query.getSingleResult();
		System.out.println(obj);
	}

7.使用hql完成分頁

hql內部是有封裝分頁的,所以分頁不需要我們自己寫,只需要提供分頁資訊就行了

        @Test
	public void testList9() {
		//資料庫為mysql
		String hql = "from Book where bookName like :bookName";
		int rows = 3;//每頁顯示3條記錄
		int page = 1;//第一頁
		Query query = session.createQuery(hql);
		query.setParameter("bookName", "%紅%");//模糊查詢
		query.setFirstResult((page-1)*rows);//從第幾條資料開始查,索引從0開始
		query.setMaxResults(rows);
		List<Book> list = query.list();
		for (Book book : list) {
			System.out.println(book);
		}
	}

8.對hql的操作進行封裝(BaseDao封裝):方便開發,減少冗餘程式碼

示例:帶條件的查詢分頁

        public List<Book> list1(Book book,PageBean pageBean){
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		String hql = "from Book where 1=1";
		if (StringUtils.isNotBlank(book.getBookName())) {
			hql += " and book_name like :book_name";
		}
		Query query = session.createQuery(hql);
		if (StringUtils.isNotBlank(book.getBookName())) {
			query.setParameter("book_name", "%"+book.getBookName()+"%");
		}
		if (pageBean != null && pageBean.isPagination()) {
			query.setFirstResult(pageBean.getStartPage());
			query.setMaxResults(pageBean.getTotalPage());
		}
		List<Book> list = query.list();
		return list;
	}

注:setParameter方法是BaseDao封裝的設定引數方法,所以程式碼中減少了賦值的程式碼,這也是BaseDao的一個好處,後面會有程式碼,這裡主要看賦值以外的

從如上程式碼可以看到,隨著查詢條件的增加,那麼對應的if判斷就會很多,因此為了減少程式碼的冗餘,可以對其進行封裝

BaseDao封裝:

package com.study.dao;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;
import org.hibernate.query.Query;

import com.zking.util.PageBean;

/**
 * BaseDao作用:
 * 	1.特定值賦值
 * 	2.分頁
 * 		1.查總記錄數
 * 		2.查詢某一頁紀錄
 * @author L
 *
 */
public class BaseDao {
	//1.引數賦值
	public void setParameter(Query query,Map<String, Object> map) {
		if (map == null || map.size() == 0) {
			return;
		}
		
		Object value = null;
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			value = entry.getValue();
			if (value instanceof Collection) {
				query.setParameterList(entry.getKey(), (Collection)value);
			}
			else if (value instanceof Object[]) {
				query.setParameterList(entry.getKey(), (Object[])value);
			}
			else {
				query.setParameter(entry.getKey(), value);
			}
		}
	}
	
	//2.1:統計記錄數
	public String getCountHql(String hql) {
		int index = hql.toUpperCase().indexOf("FROM");
		return "select count(*) " + hql.substring(index);
	}
	
	//2.2:分頁
	public List executeQuery(Session session,String hql,PageBean pageBean,Map<String, Object> map) {
		if (pageBean != null && pageBean.isPagination()) {//是分頁
			String countHql = getCountHql(hql);
			Query countQuery = session.createQuery(countHql);
			setParameter(countQuery, map);
			pageBean.setTotal(Integer.valueOf(countQuery.getSingleResult().toString()));
			
			Query pageQuery = session.createQuery(hql);
			setParameter(pageQuery, map);
			pageQuery.setFirstResult(pageBean.getStartPage());
			pageQuery.setMaxResults(pageBean.getTotalPage());
			
			return pageQuery.list();
		}
		else {//不分頁
			Query query = session.createQuery(hql);
			setParameter(query, map);
			return query.list();
		}
	}
}

BaseDao封裝好後,再進行上個案例的操作:要記得繼承BaseDao

package com.study.dao;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;

import com.study.entity.Book;
import com.study.entity.TreeNode;
import com.zking.util.PageBean;
import com.zking.util.SessionFactoryUtils;
import com.zking.util.StringUtils;

public class BookDao extends BaseDao{
	public List<Book> list2(Book book,PageBean pageBean){
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		String hql = "from Book where 1=1";
		Map<String, Object> map = new HashMap<String, Object>();
		if (StringUtils.isNotBlank(book.getBookName())) {
			hql += " and book_name like :book_name";
			map.put("book_name", "%"+book.getBookName()+"%");
		}
		List list = executeQuery(session, hql, pageBean, map);
		transaction.commit();
		session.close();
		return list;
	}
}

程式碼簡潔了不少,至少我們成功去除了重複的程式碼

9.原生sql:

應用場景:當hql不滿足需求,或者使用hql不再簡化程式碼,想要使用sql程式碼時

將createQuery(hql)->createSQLQuery(sql)方法,就能使用sql程式碼了

10.檢視對映

例:

1.select * from book a,type b a.tid = b.tid where b.tname like '%玄%'

2.select * from book a,type b a.tid = b.tid where b.tid = 1

3.select * from book a,type b a.tid = b.tid where a.bname like '%完%'

以上是三條聯表查詢語句,因為業務不同,所以有時要對錶進行不同的查詢,如果聯表的數量非常多,那麼寫sql時程式碼就會非常長,所以檢視對映就是將重複sql程式碼封裝,然後根據不同的業務,只需要寫不同的條件即可

上述程式碼中重複的地方select * from book a,type b a.tid = b.tid

步驟

1.建立一個檢視,將此程式碼進行封裝

create view aaa

as

select * from book a,type b a.tid = b.tid

2.根據業務的不同,對檢視新增不同的查詢條件

假如我要根據書名查詢

select * form aaa where bname like '%完%'

這樣就可以達到簡化程式碼的作用