1. 程式人生 > >【Hibernate步步為營】--hql查詢過濾器及相關聚合函式查詢詳解

【Hibernate步步為營】--hql查詢過濾器及相關聚合函式查詢詳解

        上篇文章討論了hql查詢中的連線查詢,它的查詢語法在功能上和sql的連線查詢是相同的,內連線查詢取得的是關係之間的笛卡爾積,外連線查詢是獲取一個關係表及與另一個關係表的合集部分,具體的使用方法見上篇文章,並在最後討論了外接命名查詢的方法。該篇文章將會對hql的引數查詢、函式查詢及查詢過濾器做詳細的討論。

一、引數查詢

        引數查詢其實是使用等價代換的方法,使用設定的值替換字串中指定位置的符號,或者通過使用引數名稱,使用字串來替換引數名稱的值,這樣能避免sql注入的問題,拼接字串會出現sql注入的問題。hql提供了兩種引數查詢的方法,一種是通過使用符號“?”,然後使用setParameter方法設定替換的字串;另外一種是使用引數名稱,定義引數名稱,並使用setParameter方法來替換指定引數名稱的字串。

 1.1 引數符號--?

        通過使用符號?來設定要新增的引數內容,也就是說這裡的符號?其實是hql的引數。如果想要為引數賦值,可以使用hql的方法setParameter,該方法過載引數,提供兩個引數,一個能夠傳遞引數出現的位置,另一個為引數賦值。具體如下程式碼:

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//方法鏈程式設計
		List students=session.createQuery("select s from Student s where s.name like ?").setParameter(0, "%0%").list();
		for(Iterator iter=students.iterator();iter.hasNext();){
			Student student=(Student)iter.next();
			System.out.println(student.getName());
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

       在需要使用引數的字串位置處使用?來代替,然後使用setParameter 方法,替換引數的內容。該方法中的第一個引數可以是字串也可以是索引,如果使用了?作為引數,就必須指定?的第幾個索引。

  1.2 引數名稱

       上文已經討論了符號引數的使用方法,並稍微簡介了引數名稱查詢的方法,也就是說可通過使用引數名稱的方法來定義引數,這種方法需要指定引數的名稱,然後使用setParameter來設定名稱替換引數,hql的引數定義是冒號+引數名。

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//可以採用 :引數名 的方式傳遞引數
		
		//方法鏈程式設計
		List students=session.createQuery("select s from Student s where s.name like :myname").setParameter("myname", "%0%").list();
		for(Iterator iter=students.iterator();iter.hasNext();){
			Student student=(Student)iter.next();
			System.out.println(student.getName());
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

        在上面的示例中使用了like模糊查詢,查詢在學生的姓名中有0出現的所有的學生資訊,查詢字串中定義了一個名稱為myname的引數,並使用setParameter為引數賦值。

  1.3 引數集合

        上文簡單介紹了hql單個引數的使用方法,非常簡單,那如果字串中需要配置多個連線的引數怎麼辦呢,那要使用setParameter一個個的進行賦值嗎?hql提供了setParameterList來為引數舒服賦值,如下示例:

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery5(){
	Session session=null;
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//可以採用 :引數名 的方式傳遞引數
		
		//方法鏈程式設計
		List students=session.createQuery("select s from Student s where s.id in(:ids)")
				.setParameterList("ids",new Object[]{1,2,3,4})
				.list();
		for(Iterator iter=students.iterator();iter.hasNext();){
			Student student=(Student)iter.next();
			System.out.println(student.getName());
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

      上例中使用了集合查詢in,在集合中查詢符合集合要求的內容,定義了名為ids的引數,引數的具體內容是一個物件集合,使用setParameterList為引數做了賦值。

二、函式查詢

        hql的具體查詢提供了基本的sql查詢方法,同樣也支援對應資料庫的函式查詢方法,可以在查詢語句中使用資料庫函式來設定查詢內容的格式及想要查詢的內容,如日期格式函式date_format:

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//日期函式
		List students=session.createQuery("select s from Student s where date_format(s.createTime,'%Y-%m')=?")
				.setParameter(0,"2009-07")
				.list();
		for(Iterator iter=students.iterator();iter.hasNext();){
			Student student=(Student)iter.next();
			System.out.println(student.getName());
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

      上例中是按照學生資訊的建立時間來查詢相應的學生資訊,通過使用date_format()方法來將字串轉化為相應查詢內容的格式來獲取的查詢內容。     

      另外也可以使用資料庫的between...and...來查詢某一範圍內的資料,如下示例查詢某一時間段內的學生資訊:

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//查詢時間段
		List students=session.createQuery("select s from Student s where date_format(s.createTime,'%Y-%m') between ? and ?")
				.setParameter(0,"2009-07")
				.setParameter(1,"2012-07")
				.list();
		for(Iterator iter=students.iterator();iter.hasNext();){
			Student student=(Student)iter.next();
			System.out.println(student.getName());
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

        聚合查詢,hql不支援*查詢,但是可以使用count(*)查詢。想要使用group by分組語句就必須在語句使用使用聚合函式。如下示例演示的是hql聚合函式和分組查詢的使用方法:

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//返回結果集屬性列表,元素型別和實體類中的屬性型別一致
		List students=session.createQuery("select c.name,count(s) from Classes c join c.students s group by c.name order by c.name").list();
		
		for(Iterator ite=students.iterator();ite.hasNext();){
			Object[] obj=(Object[])ite.next();
			System.out.println(obj[0]);
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}
       獲取第一行,hql提供了方法來獲取結果集中的第一行資料,該方法為uniqueResult(),通過使用sql語句來獲取的結果集,然後在方法鏈中使用uniqueResult()方法來獲取預設第一行的資料,如下程式碼:
<pre name="code" class="java">@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//返回結果集屬性列表,元素型別和實體類中的屬性型別一致
		//List students=session.createQuery("select count(*) from Student").list();
		//Long count=(Long)students.get(0);

		//上面的查詢方法,類似於下面使用的uniqueResult()方法
		Long count=(Long)session.createQuery("select count(*) from Student").uniqueResult();
		System.out.println("count="+count);
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

      上面的程式碼示例提供了兩種方法來獲取第一行的資料,一種是通過使用get()方法,獲取結果集中的第幾行的內容;另外一種使用的是uniqueResult()方法來獲取新行的內容。

三、查詢過濾器

       查詢過濾器提供了對查詢的內容進行過濾的過程,在對映檔案中定義過濾器,程式中啟用過濾器,併為過濾器引數賦值。具體步驟為:首先在要查詢的實體物件的對映中使用<filter-def>標籤配置過濾器,並在相對應的<class>標籤中新增對應的<filter>過濾器;然後在對應的程式檔案中使用enableFilter()方法啟動過濾器,為過濾器定義的引數賦值,在執行時就會自動自行對應的過濾器。

       清單一:對映檔案,在對映檔案中配置對應的過濾器,對映檔案中定義了名為testFilter的過濾器,在class中為過濾器添加了執行條件,並在條件中添加了執行引數myid。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.src.hibernate.Student" table="t_student">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<property name="createTime"></property>
		<!-- 在多的一端Student中新增一行新的Classes列 ,並且列的名稱要和Classes.hbm.xml的列明相同-->
		<many-to-one name="classes" column="classesid"></many-to-one>
		<!-- 使用過濾器,指定id的內容要小於引數:myid配置的內容-->
		<filter name="testFilter" condition="id < :myid"></filter>
	</class>
	
	<!-- 定義查詢過V領器 -->
	<filter-def name="testFilter">
		<filter-param type="integer" name="myid"></filter-param>
	</filter-def>
</hibernate-mapping>
       清單二:程式檔案,在程式檔案中使用enableFilter啟用過濾器,併為過濾器的引數賦值。
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testQuery(){
	Session session=null;
	
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		session.enableFilter("testFilter").setParameter("myid",10);
		//返回結果集屬性列表,元素型別和實體類中的屬性型別一致
		List students=session.createQuery("from Student").list();
		
		for(Iterator ite=students.iterator();ite.hasNext();){
			Student obj=(Student)ite.next();
			System.out.println(obj.getName());
		}
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

結語

        hql的基本查詢方法已經討論完成,主要針對hql的使用過程中需要注意的內容作了詳細的討論,在每一種查詢方法中都添加了相應的示例,通過示例加深對hql查詢方法的使用,有sql基礎的在使用hql時會非常的簡單。