看這個鏈接作了解:http://zhaohe162.blog.163.com/blog/static/3821679720110251181721/
一、HQL查詢的from子句
from是最簡單的語句,也是最基本的HQL語句。from關鍵字后緊跟持久化類的類名。
例如:
from Person
推薦為Person持久化類的每個實例起別名,例如:
from Person as p
p作為Person的實例的別名,因此也應該遵守Java的命名規則:第一個單詞的首字母小寫,后面每個單詞的首字母大寫。
命名別名時,as關鍵字是可選的,但為了增加可讀性,建議保留。
from 后還可同時出現多個持久化類,此時將產生一個笛卡爾積或跨表的連接,但實際上這種用法很少使用,因為通常我們可能需要使用跨表的連接,此時可以考慮使用隱式連接或顯示連接,而不是直接在from后緊跟多個表名。
二、關聯和連接
隱式連接形式不適用join關鍵字,使用英文點號(.)來隱式連接來關聯實體,而Hibernate底層將自動進行關聯查詢。如下HQL語句:
from Person p where p.myEvent.title > :title
上面的p.myEvent屬性的實質是一個持久化實體,因此Hibernate底層隱式地自動進行連接查詢。
顯示連接則需要使用xxx join關鍵字,例如如下語句:
//使用顯示連接
from Person p
inner join p.myEvent event
where event.happenDate < :endDate
使用顯示連接時,可以為相關聯的實體,甚至是關聯集合中的全部元素指定一個別名。
Hibernate支持的HQL連接類型,可使用如下幾種連接方式:
inner join(內連接),可簡寫成join。
left outer join(左外連接),可簡寫成left join。
right outer join(右外連接),可簡寫成right join。
full join(全連接),并不常用。
使用顯示連接時,還可通過HQL的with關鍵字來提供額外的連接條件,例如如下HQL語句:
from Person p
inner join p.myEvent event
with p.id > event.id
where event.happenDate < :endDate
三、隱式連接和顯示連接有如下兩點區別:
(1)隱式連接底層轉換成SQL92的內連接,顯示連接層將轉換成SQL99的多表連接。
(2)隱式連接和顯示連接查詢后返回的結果不同。
當HQL語句中省略select關鍵字時,使用隱式連接查詢返回的結果是多個被查詢實體組成的集合。
當HQL語句中省略select關鍵字時,使用顯示連接查詢返回的結果也是集合,但集合元素是被查詢持久化對象、所有被關聯的持久化對象所組成的數組。
使用fetch關鍵字時,有如下幾個注意點:
程序里希望預加載那些原本應延遲加載的屬性,則可以通過fetch all properties來強制Hibernate立即抓取這些屬性。例如:
from Document fetch all properties order by name
四、HQL查詢的select子句
(1)select子句用于選擇指定的屬性或直接選擇某個實體,當然select選擇的屬性必須是from后持久化類包含的屬性。
例如:
select p.name from Person as p
(2)select可以選擇任意屬性,即不僅可以選擇持久化類的直接屬性,還可以選擇組件屬性包含的屬性。例如:
select p.name.firstName from Person as p
(3)在特殊情況下,如果select后只有一項(包括持久化實例或屬性),則查詢得到的集合元素就是該持久化實例或屬性。
(4)如果select后有多個項,則每個集合就是選擇出的多項組成的數組。
例如:
select p.name,p from Person as p
執行該HQL語句得到的集合元素時類似于[String,Person]結構的數組,其中第一個元素時Person實例的name屬性,第二個元素時Person實例。
注意:即使select后的列表項選出某個持久化類的全部屬性,這些屬性依然是屬性,Hibernate不會將這些屬性封裝成對象。只有在select后的列表里給出持久化類的別名(其實就是實例名),Hibernate才會將該項封裝成一個持久化實體。
(5)select支持將選擇出的屬性存入一個List對象中。
例如:
select new list(p.name, p.address) from Person as p
例如:
select new ClassTest(p,name, p.address) from Person as p;
而ClassTest必須有如下的構造器:ClassTest(String s1, String s2)
(7)select還支持給選中的表達式命名別名。例如:
select p.name as personName from Person as p
這種用法與new map 結合使用更普遍。例如:
select new map(p.name as personName) from Person as p
執行上面的HQL語句返回的結果是集合,其中集合元素時Map對象,以personName作為Map的key,實際選出的值作為Map的value。
五、HQL查詢的聚集函數
HQL支持的聚集函數與SQL的完全相同:avg,count,max,min,sum。
例如,如下的HQL語句:
select count(*) from Person
select max(p.page) from Person as p
select子句還支持字符串連接符、算術連接符,以及SQL函數。例如:
select p.name||""||p.address from Person as p
select子句也支持使用distinct和all關鍵字,此時的效果與SQL的效果完全相同。
六、多態查詢
如下面的查詢語句:from Person as p
如下面的查詢語句:from Named as n
注意:上面最后一條查詢,需要多個SQL SELECT 語句,因此無法使用order by子句對結果集排序,從而不允許對這些查詢結果使用Query.scroll()方法。
七、HQL查詢的where子句
(1)where子句用于篩選選中的結果,縮小選擇的范圍。如果沒有為持久化實例命名別名,則可以直接使用屬性名來引用屬性。
如下面兩條HQL語句:
from Person where name like "tom%"
form Person as p where p.name like "tom%"
(2)復合屬性表達式加強了where子句的功能,例如,如下的HQL語句:
from Cat cat where cat.mate.name like "kit%"
上面語句被翻譯成以下含有內連接的SQL查詢:
select * from cat_table as table1 cat_table as table2
where table1.mate = table2.mate
and table1.name like '''kit%'"
實際上這種用法使用了隱式連接查詢,從Hibernate3.2.3之后,只有當cat,mate屬性引用的是普通組件屬性或者單獨的關聯實體時才可接著在后面使用點好(.)來引用mate屬性,如cat,mate.name;如果cat,mate是集合屬性,Hibernate3.2.3以后的版本不支持這種用法。
"="號不僅可以被用來比較屬性的值,也可以用來比較實例。
select cat,mate from Cat cat, Cat mate where cat.mate = mate
(3)在進行多態持久化的情況下,class關鍵字用來存取一個實例的鑒別值。嵌入where子句的Java類名,將被作為該類的鑒別值。
//執行多態查詢時,默認會選出Cat及其所有子類的實例
//在如下HQL語句中,將只選出DomesticCat類的實例
from Cat cat where cat.class = DomesticCat
(4)當where子句中的運算符只支持基本類型或者字符串時,where子句中的屬性表達式必須以基本類型或者字符串結尾,不要使用組件類型屬性結尾,例如Account和Person屬性,而Person有Name屬性,Name屬性有firstName屬性。
如下所示:
//firstName是字符串
from Account as a where a.person.name.firstName like "dd%"
//下面是錯誤實例
from Account as a where a.person.name like "dd%"
八、表達式
1、HQL的功能非常豐富,where子句后支持的運算符,不僅包括SQL的運算符,也包括EJB-QL的運算符等。
where子句中允許使用大部分SQL支持的表達式,包括如下種類:
(1)字符串連接:如value1||value2,或使用字符串連接函數concat(value1, value2)
(2)簡單的case,case...when...then...else...end和case,case when...then...else...end等。
(3)時間操作函數:current_date()、current_time、year()等。
(4)EJB-QL3.0的函數:substring()、trim()、abs()、sqrt()等。
(5)可在where子句中使用SQL常量。
(6)在HQL語句中使用Java中的public static final類型的常量,例如Color.RED
(7)HQL語句支持使用英文問號(?)作為參數占位符,這與JDBC的參數占位符一致;也使用命名參數占位符號,方法在參數名前加英文冒號(:),例如:start_date等。
(8)如果底層數據庫支持單行函數,則HQL語句也完全可以支持。
(9)支持數據庫的類型轉換函數,如cast(... as ...),第二個參數是Hibernate的類型名,或者extract(... from ,,,),前提是底層數據庫支持ANSI cast()和extract()。
2、如果在Hibernate配置文件中進行如下聲明:
<property name="hibernate.query.substitutions">true 1,false 0</property>
上面的聲明表明:HQL轉換SQL語句時,將使用字符1和0來取代關鍵字true和false,然后將可以在表達式中使用布爾表達式。
3、有用的elements()和indices函數,用于返回指定集合的所有元素和所有索引。
4、在where子句中,有序集合(數組、List集合、Map對象)的元素可以通過【】運算符來訪問。如下:
from Order order where order.items[0].id=1234
在【】中的表達式甚至可以是一個算式表達式。
5、結構變量:size、elements、indices等,只能在where子句中使用。
九、order by子句
查詢返回的集合根據類或組件屬性的任何屬性進行排序。例如:
from Person as p order by p.name,p.age
還可以使用as或desc關鍵字指定升序或降序的排序規則。例如:
from Person as p order by p.name asc,p.age desc
如果沒有指定排序規則,默認采用升序規則。
十、group by子句
返回聚集值的查詢可以對持久化類或組件屬性的進行分組,分組使用group by子句。看下面的HQL查詢語句:
select cat,color,sum(cat.weight),count(cat) from Cat cat group by cat.color
其規則類似于SQL規則。
having子句用于對分組進行過濾,如下所示:
select cat,color,sum(cat.weight),count(cat) from Cat cat group by cat.color having cat.color in (eg.Color.TABBY,eg.Color.BLACK)
注意:group by子句與order by 子句中都不能包含算術表達式
十一、子查詢
(1)如果底層數據庫支持子查詢,則可以在HQL語句中使用子查詢。如下:
from Cat as fatcat where fatcat.weight > (select avg(cat.weight) from DomesticCat cat)
(2)如果子查詢是多行結果集,則應該使用多行運算符。如下:
from Cat as cat where not(cat.name, cat.color) in (select cat.name, cat.color from DomesticCat cat)
(3)SQL語法中子查詢還可以出現在select子句之后,HQL也支持這種用法,看如下HQL語句:
select cat.id,(select max(kit.weight) from cat.kitten kit)
from Cat as cat
注意:HQL子查詢只可以在select子句或者where子句中出現。
十二、命名查詢
HQL支持將查詢所用的HQL語句放入配置文件中,而不是代碼中。
在Hibernate映射文件的<hibernate-mapping/>元素中使用<query/>子元素來定義命名查詢,使用<query/>元素只需要指定一個name屬性,指定該命名查詢的名字。該元素的內容就是命名查詢的HQL語句。如下配置文件片段:
<query name="myNameQuery">
</query>
配置好后,通過Session提供的一個getNameQuery(String name)方法,該方法用于創建一個Query對象,剩下的操作與普通HQL完全一樣。如下所示:
List p1 = sess.getNamedQuery("myNameQuery").setInteger(0,20).list()
十三、條件查詢
條件查詢通過如下3個類完成:
Criteria:代表一次查詢。
Criterion:代表一個查詢條件。
Restrictions:產生查詢條件的工具類。
執行條件查詢的步驟如下:
(1)獲得Hibernate的Session對象。
(2)以Session對象創建Criteria對象。
(3)使用Restrictions的靜態方法創建Criterion查詢條件。
(4)向Criteria查詢中體檢Criterion查詢條件。
(5)執行Criteria的list等方法返回結果集。
代碼片段如下:
List l = session.createCriteria(Student.class)
在條件查詢中,Criteria接口代表依次查詢,該查詢本身不具備任何的數據篩選功能,Session調用createCriterial(Class clazz)方法對某個持久化類創建條件查詢實例。
Criteria對象不具備任何的數據篩選功能,但程序可以通過向Criteria對象中組合多個Criterion(每個Criterion對象代表一個過濾條件)即可實現數據過濾了。
Criterion接口代表一個查詢條件,該查詢條件由Restrictions負責產生。Restrictions是專門用于產生查詢條件的工具類,它的方法大部分都是靜態方法,常用的方法如下:
(1)static Criteion allEq(Map propertyNameValues):判斷指定屬性(由Map參數的key指定)和指定值(由Map參數的value指定)是否完全相等。
(2)static Criterion between(String propertyName, Object lo, Object hi):判斷屬性值在某個指范圍之內。
十四、關聯和動態關聯
代碼片段如下:
List l = session.createCriteria(Student.class)
上面的代碼表示建立Person類的條件查詢,第一個查詢條件是直接過濾Person的屬性。第二個查詢條件則過濾Person的關聯實體的屬性,其中enrolments是Person類的關聯實體,而semester則是Enrolment類的屬性。值得注意的是,返回的并不是Enrolment對象,而是Person對象的集合。
注意:使用關聯類的條件查詢,依然是查詢原有持久化類的實例,而不是查詢被關聯類的實例。
可使用條件查詢支持的替換形態,將上面查詢代碼替換成如下形式:
List l = session.createCriteria(Student.class)
createAlias()方法并不創建一個新的Criteria實例,它只是給關聯實體(包含集合里包含的關聯實體)起一個別名,讓后面過濾條件可根據關聯實體進行篩選。
在默認情況下,條件查詢將根據映射文件指定的延遲加載策略來加載關聯實體,如果希望在條件查詢中改變延遲加載策略(就像在HQL查詢中使用fetch關鍵字一樣),那就可通過Creteria的setFetchMode()方法來實現,該方法接受一個FetchMode參數。
FetchMode里有幾個常量,如下:
DEFAULT:使用配置文件制定的延遲加載策略處理。
JOIN:使用外連接,預初始化所有關聯實體。
SELECT:啟用延遲加載,系統將使用單獨的select語句來初始化關聯實體。只有當個真正訪問關聯實體的時候,才會執行第二條select語句。
初始化Student對象時,也可以初始化Student關聯的Enrolment實體,實體使用如下代碼:
List l = session.createCriteria(Student.class)