Hibernate學習_017_Hibernate查詢語言(QL)的幾點說明

在Hibernate整個查詢體系中,存在以下幾種查詢語言:NativeSQL、HQL、EJBQL(JPQL)、QBC、QBE。他們之間的關係式NativeSQL>HQL>EJBQL(JPQL)>QBC>QBE。可以簡單認爲後者爲前者的子集,NativeSQL功能最爲強大。下面對於在Hibernate中用的查詢需要注意的幾點做一個總結:

第一:NativeSQL 與本地數據庫有關,由於是針對具體數據庫,所以不可以跨越數據庫平臺,但是也是功能最爲強大和最爲靈活的。一般在做本地報表系統的時候,會大量的使用NativeSQL。

第二:HQL,Hibernate Query Language ,這種語句在執行的時候,在系統內部會根據設置的Hibernate方言將其轉化爲具體的本地SQL。

第三:EJBQL(JPQL),95%以上的時候,都是使用的這個查詢語言,而且可以跨越ORMapping平臺。而且EJBQL是導航性質的。

第四:QL應該與導航關係相結合,共同爲查詢提供服務。

第五:關於分頁的實現:Oracle中使用三層嵌套實現,SQL使用Limit,而在HQL中使用的setMaxResult()和setFirstResult()兩個方法來實現。

第六:一個面試題:JAVA中有沒有內存泄露?其實,java在語法級別是沒有內存泄露的,但是在實際運用中,會存在內存泄露的情況,比如這樣一個場景,在一個有上千萬條數據的表中,不斷分頁取出數據,試想一下,每次取出一百條,如果處理完成之後,不手動的執行session.clear()清理內存,這個時候由於內存中有數據的引用,這個時候,垃圾收集器是不會主動去回收內存,這樣,在不斷的分頁取出數據的時候,一定時間以後,內存就會被佔滿。還有一個問題需要說明是:爲什麼java打開的文件一定要手動關閉?原因是JAVA打開一個文件操作實際是調用了底層的C來完成的,然後C再去調用windows API執行相關的操作,但是雖然JAVA有內存垃圾回收機制,但是C卻沒有這種機制。所以,JAVA打開的文件一定要手動的去關閉。

下面就常用的QL用法做一個總結說明:

1:HQL採用面向對象的思維,直接通過類取對象:比如  Query query = session.createQuery("from Category");

2:從面向對象的角度,在1的基礎上添加各種過濾條件:比如 Query q = session.createQuery("from Category c where c.name > 'c5'");

3:從面向對象的角度,在1的基礎上添加排序:Query q = session.createQuery("from Category c order by c.name desc");

4:過濾重複值:Query q = session.createQuery("select distinct c from Category c order by c.name desc");

5:設定過濾條件參數(兩種方式可選 ? 和 :xxx):

5.1:Query q = session.createQuery("from Category c  where c.id > :min and c.id < :max order by c.name desc").setParameter("min", 3).setParameter("max", 6);

5.2:Query q = session.createQuery("from Category c  where c.id > ? and c.id < ? order by c.name desc").setParameter(0, 3).setParameter(1, 6);

6:只選取對象中的特定列組成對象數組:

		Query q = session.createQuery("select c.id , c.name from Category c");
		List<Object[]> categories = (List<Object[]>)q.list();
7:通過對象導航實現查詢:Query q = session.createQuery("from Topic t where t.category.id = 1");
8:將查詢出來的值組裝成VO對象:比如:Query q = session.createQuery("select new com.zxb.model.MsgInfo(m.id, m.cont, m.topic.title, m.topic.category.name) from Msg m");注意,這裏的MsgInfo對象在數據庫中是不存在對應表的,只是程序中用來完成特定功能的一個輔助工具類,比如VO ,DTO一般都屬於這類對象。

9:表之間的鏈接查詢:比如:Query q = session.createQuery("select t.title, c.name from Topic t join t.category c");注意,這裏的t.category c不可以是Category c,因爲在Topic 可能存在多個類型爲Category的屬性,這樣寫的話就不知道到底是以那個屬性作爲鏈接條件使用了。必須通過t.屬性名的形式指定具體是那個屬性作爲鏈接條件。

10:UniqueResult的使用:使用的過濾條件可以是傳入的一個對象。示例代碼如下:

Query q = session.createQuery("from Msg m where m = :MsgToSearch "); //不重要
		Msg m = new Msg();
		m.setId(1);
		q.setParameter("MsgToSearch", m);
		Msg mResult = (Msg)q.uniqueResult();
11:在HQL中,雖然從面向對象的角度考慮,但是sql中很多特性依舊可用,比如,聚合函數,between , in 等,例如:

Query q = session.createQuery("select count(*) from Msg m");

Query q = session.createQuery("select max(m.id), min(m.id), avg(m.id), sum(m.id) from Msg m");

Query q = session.createQuery("from Msg m where m.id between 3 and 5");

Query q = session.createQuery("from Msg m where m.id in (3,4, 5)");

Query q = session.createQuery("from Topic t where t.title like '_5'");

Query q = session.createQuery("select lower(t.title)," + "upper(t.title)," +"trim(t.title)," +"concat(t.title, '***')," + "length(t.title)" + " from Topic t ");

Query q = session.createQuery("select t.title ,count(*) from Topic t group by t.title");

Query q = session.createQuery("from Topic t where exists (select m.id from Msg m where m.topic.id=t.id)") ;

12:null 、not null、 empty 、 not empty的說明,在HQL中,null 和 not null 是判斷對象的非集合屬性是否爲空,而empty 和 not empty使用來判斷對象的集合屬性是否有值,即集合的長度是否是0,而不是說空與非空,概念完全不一樣。

Query q = session.createQuery("from Msg m where m.cont is not null"); 判斷m的cont屬性是否是空值。

Query q = session.createQuery("from Topic t where t.msgs is empty");判斷t這個對象的集合屬性msgs的大小是否是0。

13:特別說明一個HQL語句:

Query q = session.createQuery("select current_date,current_time,current_timestamp ,t.id from Topic t");

這個hql語句中,取得的是數據庫的當前日期,時間以及時間戳信息,一般我們會認爲,服務器在數據庫服務器中取得這些當前信息有意義嗎?服務器去取得自己的這些信息不就ok了嗎?但是如果說在集羣環境下,這個時候,多個服務器需要通過時間信息相互協作,這個時候,有可能各個服務器的時間信息並不是一致的,這個時候就會出問題,但是如果都以數據庫服務器中的時間信息爲準的話,就不會存在問題。

14:命名sql: 這種方式,類似於配置文件的配置方式,先配好語句,用到的時候填充條件。比如。我們在要查詢的類上加上如下配置:(目前爲止:JAP還不支持@NameNativeQuery.)

@Entity
@NamedQueries({
@NamedQuery(name="topicQuery",query="from Topic t where t.id = :id")
})
/*@NamedNativeQueries({
	@NamedNativeQuery(name="topicNativeQuery", query="select * from topic limit 2, 5")
})*/
public class Topic {
	private int id;
	private String title;
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	public String getTitle() {
		return title;
	}
	public void setId(int id) {
		this.id = id;
	}
	public void setTitle(String title) {
		this.title = title;
	}
}
由於我們配置了一條根據ID來查詢Topic類實例的命名語句,所以程序中每次我們要根據id取得topic實例的時候,我們就不需要每次都寫HQL語句了。只需要取得這個命名QL語句,然後填充條件即可。如下代碼所示:

@Test
	public void testNameQuery() {
		Session session = this.sessionFactory.openSession();
		session.beginTransaction();
		Query q = session.getNamedQuery("topicQuery");
		q.setParameter("id", 5);
		Topic t = (Topic)q.uniqueResult();
		System.out.println(t.getTitle());
		session.getTransaction().commit();
		session.close();
	}
15:QBE查詢方式示例代碼:

public void testQBE(){
		Session session = this.sessionFactory.openSession();
		session.beginTransaction();
		Topic topic = new Topic();
		topic.setTitle("T_");
		Example example = Example.create(topic).enableLike().ignoreCase();
		Criteria criteria = session.createCriteria(Topic.class)
				.add(Restrictions.ge("id", 2))
				.add(Restrictions.le("id", 9))
				.add(example);
		List<Topic> topics = (List<Topic>)criteria.list();
		for(Topic t :topics ){
			System.out.println(t.getTitle());
		}
		session.getTransaction().commit();
		session.close();
	}
16:QBC查詢方式示例代碼:

public void testQBC(){
		Session session = this.sessionFactory.openSession();
		session.beginTransaction();
		Criteria criteria = session.createCriteria(Topic.class)
				.add(Restrictions.gt("id", 2))
				.add(Restrictions.lt("id", 8))
				.add(Restrictions.like("title", "t_"))
				.createCriteria("category")
				.add(Restrictions.between("id",1,5));
		List<Topic> topics = (List<Topic>)criteria.list();
		for(Topic t :topics ){
			System.out.println(t.getTitle());
		}
		session.getTransaction().commit();
		session.close();
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章