12.1 HQL語言基礎Hibernate查詢語言為HQL(Hibernate Query Language),可以直接使用實體類名及屬性。HQL語法類似于SQL,有SQL的關鍵詞如select、from、order by、count()、where等等。不同的是HQL是一種完全面向對象的語言,能夠直接查詢實體類及屬性。12.1.1 HQL語法HQL語法類似于SQL,是一種select...from...的結構。其中,from后跟的是實體類名,而不是表名。select后面跟的可以是實體對象,也可以使實體對象的屬性或者其他值,例如:Query query = session.createQuery(" select * from Users as users ");// 查詢所有的UsersList list = query.list(); // 執行查詢,返回List其中,Users為實體類Users,users為Users對象,關鍵詞as用法同SQL,可以省略。Query是Hibernate的查詢對象,query.list()將以List類型返回查詢結果。上述查詢也可以簡寫為:Query query = session.createQuery(" from Users "); // 查詢所有的UsersList list = query.list(); // 執行查詢,返回List12.1.2 HQL中的大小寫HQL語言大小寫不敏感,“select * from Users as users”也可寫作“SELECT * FROM Users as users”。但是涉及到Java類名、package名、屬性名時,需要區分大小寫,因此Users必須與類名一致。12.1.3 查詢中使用包名一個工程中,如果不存在相同的實體類名,查詢語句中實體類所在的package可省略。Hibernate會能夠根據類名檢索到實際的t實體類。但如果有相同的實體類名,查詢時必須攜帶package信息,否則Hibernate不知道使用哪一個實體類。使用包名的查詢語句實例代碼如下:SELECT users FROM com..java.vo.Users users12.1.4 查詢結果的返回類型Hibernate使用Query對象進行查詢。Session的createQuery方法能夠創建Query實例,參數為HQL。Query對象能夠返回各種類型的查詢結果,例如long、String、List<</font>實體類名>、List、POJO等。最常用的查詢方法有uniqueResult()與list()等。其中uniqueResult()返回單個值,而list()返回零個或者多個值。下面分別介紹uniqueResult()與list()。1. uniqueResult()返回單個值Query的unique()返回單個的對象。使用unique()獲取返回值時,HQL語句查詢到的結果最多只能有一個,如果結果多于一個,unique()方法會拋出異常。如果沒有,會返回null。這個方法常常用來查詢記錄總數,因為總會返回一個對象,并且也只有一個。例如:Query q = session.createQuery(" select count(*) from Users "); // 創建查詢對象Number num = (Number)q.uniqueResult(); // 返回單個實例int count = num.intValue(); // 返回數值查詢總數時,HQL格式必須為“select count(*) from Users”的格式。返回值可能為Short、Integer、Long、BigInteger等各種類型,具體返回類型根據主鍵的類型而定。這里可以用所有數值類型的父類Number類型。2. list()返回集合Query的list()方法是最常用的方法。實際上,unique()方法也是在list()方法得到返回數據后執行的。list()總是返回一個java.util.List對象,里面有零個或者多個值。list()可以返回實體對象,也可以返回實體對象的某屬性或者某些屬性。例如:List<</span>Users> list1 = session.createQuery(" select * from Users ").list();List list2 = session.createQuery(" select users.name from Users users ").list();List nlist3 = session.createQuery(" select users.name, users.dept.name from Users users ").list();List<</span>Users>list4 = session.createQuery(" select users.dept from Users users ").list();第一個查詢返回存儲著Users對象的List。第二個查詢返回存儲著Users的name值(String類型)的List。第三個查詢返回存儲著由Users的name值、Users對應的Dept的name值組成的字符串數組(String[]類型)的List。第四個查詢返回存儲著Users對應的Dept的List,雖然是Users的一個屬性,但仍然是Users類型。12.2 查詢結果同時返回多個對象Query的list()方法返回java.util.List對象。List中一般存儲完整的實體類對象。例如“select * from Users”,會將所有的Users都查詢出來,包含Users類的所有即時加載的屬性。對于有些查詢,只需要查詢幾個屬性就夠了,而不需要查詢所有的實體類屬性。這時候可以在HQL中指定要返回的部分。查詢部分屬性時,返回結果仍然是List類型,里面可能是單個的對象Object,也可能是對象數組Object[],還可能是List對象與Map對象。返回什么樣的類型數據,由HQL語句決定。12.2.1 返回List集合返回結果還可以放到List中。查詢時HQL采用“select new List(name1, name2, name3) from...”的形式。同樣需要遍歷List來獲取返回的List,再遍歷返回的List獲取查詢結果,實例代碼如下:// 查詢三個字段,放入一個新的List集合中,再返回List集合對象list1List list1 = session.createQuery(" select new List(u.name, u.address,u.passWord) from Users u").list();for (List li : list1) { // 遍歷第一層List集合for (Object o : li) { // 遍歷第二層List集合(保存3個字段的集合)System.out.分頁顯示查詢結果、級聯查詢以及其他的應用。12.3.1 條件查詢HQL用where連接條件子句,語法類似于SQL。大部分SQL的規則對于HQL都適用,例如等于(=)、大于(>)、小于(<</font>)等。HQL的where子句中使用的是實體類的屬性,或者是屬性的屬性。查詢條件可以寫在HQL中,也可以通過Query設置參數,示例代碼如下:session.createQuery(" select * from Users "+ " where u.dept.name = null and u.age < :age ").setParameter("age", 23).list();HQL的where子句中可以使用的運算符如下:q 數學運算符:+、-、*、/。q 比較操作符:=、!=、<>、>=、<=、like。q 邏輯計算法:and、or、not。q SQL操作符:in、not in、between、is null、is not null、is empty、number of等。q 字符串連接:...||...或者concat(..., ...)。q 時間日期函數:current_date()、current_time()、current_timestamp()。q 時間日期函數:second(...)、minute(...)、hour(...)、day(...)、month(...)、year(...)。q JPA定義的操作:substring()、trim()、lower()、upper()、length()、locate()、abs()、sqrt()、bit_length()、coalesce()、nullif()。q 數據庫支持的SQL標量函數:sign()、trunc()、rtrim()、sin()。q 簡單的跳轉語句:case ... when ... then ... else ... end。例如字符串連接:List list = session.createQuery(" select u.name || '所在部門為' || u.dept.name from Users u where u.dept != null ").list();in子句查詢:List<</span>Users> list = session.createQuery(“ from Users where lower(trim(uu.name)) in (‘Jack’, ‘Macle’, ‘李四’) ”).list();集合查詢:List<</span>Users> list = session.createQuery(“ from Users u where size(u.events) > 5 ”).list();設置查詢條件時,應盡量使用setParameter()傳遞參數,而不是將參數寫進HQL語句。第一次執行SQL語句時,數據庫會將該SQL語句進行編譯,供下次查詢使用。對于參數不同的相同查詢,數據庫將直接調用編譯后的SQL,提高查詢效率。12.3.2 HQL中的統計函數跟SQL一樣,Hibernate也提供一系列的統計函數。Hibernate會把HQL的統計函數轉化為底層數據庫SQL支持的函數。SQL里的常用統計函數比如count()、sum()、min()、max()、avg()、count(distinct ...)等也都能用在HQL里,語法與SQL一樣,例如:Number num = (Number) session.createQuery(" select count(*) from Users u where u.name != null ").uniqueResult();int count = num.intValue(); 查詢總數時并不總是返回Long類型。返回值類型由實體類的主鍵類型決定的。如果實體類的主鍵為short類型,則返回值可能為Integer類型。12.3.3 HQL分頁顯示查詢結果分頁顯示是web數據庫程序必備的功能。不同的數據庫使用不同的方式實現分頁,例如MySQL使用limit,Oracle使用rownum。Hibernate隱藏了所有的細節,只需要設置當前頁數即可。分頁顯示一般先查詢記錄總數,然后查詢本頁顯示的記錄。Hibernate通過Query查詢記錄,Query通過setFirstResult()設置分頁的第一條記錄,通過setMaxResults()設置取本頁的數據數,示例代碼如下://HQL的分頁查詢Query q2 = session.createQuery("from Employees");//查詢所有記錄int page=1; //設置默認的頁數為1q2.setFirstResult((page-1)*2); //每頁起始數q2.setMaxResults(5); //每頁最最多顯示的頁數List emps = q2.list();//返回list集合for (Employees emp:emps) {System.out.println(emp.getEmployeeId());//打印輸出屬性}分頁顯示一般會封裝成Pagination組件。Pagination負責計算每頁的起始記錄、總頁數等。使用實例見Servlet章節。查詢總數時并不總是返回Long類型。返回值類型由實體類的主鍵類型決定的。如果實體類的主鍵為short類型,則返回值可能為Integer類型。12.3.4 HQL跨表查詢對于一般的跨表查詢,表連接就足夠了。Hibernate支持用“.”作為操作符獲取屬性,用法類似于jsp中的EL表達式。表連接查詢適用于非集合屬性,對于一般的跨表查詢,只需要簡單的使用屬性就可以了。例如Users的name屬性,Dept的name屬性等,示例代碼如下:List<</span>Users> list = session.createQuery(" select * from Users u where u.dept.name = 'Java開發部' ").list();表面上該查詢只涉及Users表,但實際上因為where子句條件用到了u.dept.name,將會查詢Dept表與Users表。12.3.5 HQL級聯查詢有些查詢需要使用級聯查詢。HQL支持SQL的級聯查詢,包括inner join、left join、right join、full join等。級聯查詢適用于集合屬性,例如Users的dept集合屬性。例如查詢events集合屬性中有“遲到”事件的cat,查詢語句為:List<</span>Users> list = session.createQuery(" select * from Users u left join u.events e where e.description like :description ").setParameter("description", "%遲到%").list();12.3.6 使用數據庫SQLHQL可以看作是是對所有數據庫SQL的封裝。HQL提供的功能是底層數據庫SQL支持的,HQL只是將功能“翻譯”成了底層SQL的功能。有些情況下,底層數據庫會提供某種功能,但是可能HQL不支持。這時可以使用底層SQL,在專業術語上叫做本地SQL(Native SQL)。使用數據庫SQL查詢時不能使用Query,要使用SQLQuery對象。例如在MySQL數據庫中查詢所有的變量:SQLQuery sqlQuery = session.createSQLQuery(" show variables "); // 使用本地SQL查詢所有的變量List list = sqlQuery.list(); // 執行查詢,把查詢結果放到List集合中for (Object[] object : list) { // 遍歷集合中所有的屬性System.out.println(object [0] + ", " + object [1] + ", "); // 輸出對象屬性值}SQLQuery與Query一樣,都也可以設置參數、分頁顯示等。SQLQuery返回的結果為List類型。也可以設置為實體類,使查詢結果直接返回實體類對象,示例代碼如下:SQLQuery sqlQuery = session.createSQLQuery(" select * from users"); // 使用本地SQL查詢sqlQuery.addEntity(Users.class); // 設置輸出類型括號中是實體類名List< Users > list = sqlQuery.list(); // 返回List< Users >如果設置的實體類與查詢結果不一致,會拋出異常。12.3.7 使用@注解配置命名查詢有些查詢是常用的,Hibernate中可以把常用的查詢命名,需要使用查詢時只需要引用名稱就可以了。命名查詢一般配置在實體類中。有使用@注解配置命名查詢和使用xml配置命名查詢。使用@注解配置實體類時,要使用@注解配置命名查詢,用到的Java注解為@NamedQuery與@NamedNativeQuery。其中,@NamedQuery用于配置命名的HQL查詢,@NamedNativeQuery用于配置命名的底層數據庫SQL查詢,實體類中的代碼如下:import javax.persistence.*;@NamedQuery(name = "all users", query = " select * from Users")// 命名查詢,name是查詢語句的名稱@NamedNativeQuery(name = "all users", query = "select * from users") // 命名本地查詢@Entity // Entity配置@Table(name = "users") // Table配置public class Users {//這里省略了類中的內容}上述代碼中,命名查詢的查詢語句中Users是實體類的名稱,命名本地查詢的查詢語句中users是數據庫表名。12.3.8 使用@QueryHint擴展查詢命名查詢中,允許使用@QueryHint對命名查詢設置JPA擴展。JPA規范允許對JPA進行一些功能上的擴展,以加速查詢性能、提供其他功能等。示例代碼如下:@NamedQuery(name = "all users name", query = " select * from Users u where u.name = :name ", hints = { @QueryHint(name = "org.hibernate.callable", value = "true") })使用@QueryHint時,要把@QueryHint寫在hints中,hints的格式是“hints={}”,需要寫的@QueryHint內容寫在大括號中。org.hibernate.callable 的布爾變量值表明這個查詢是否是一個存儲過程。value=”true”表示這個查詢是存儲過程。12.3.9 同時設置多個命名查詢一個實體類不能配置多個@NamedQuery。如果有多個命名查詢,需要使用@NamedQueries配置。@NamedQueries中可以配置多個@NamedQuery,示例代碼如下:@NamedQueries(value = {@NamedQuery(name = "all users", query = " select u from Users u "),@NamedQuery(name=" users name", query=" select u from Users u where u.name = :name ",),@NamedQuery(name=" users for dept",query="select u from Users u where u.dept.name = :dept ") })當需要使用到命名查詢的時候,直接在程序中調用,程序中這樣使用命名查詢,如果有參數,需要設置參數,示例代碼如下:Query query = session.getNamedQuery("users name ").setParameter(“name”, “Jack”);List<</span>Users> list = query.list();12.3.10 在XML中配置命名查詢如果實體類使用XML文件配置映射關系時,命名查詢需要配置在hbm.xml實體類映射文件中。命名查詢使用配置,要配置中實體類的后面,name配置查詢的名稱,可配置返回數據的類型。示例代碼如下:
<?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 package="com. java.vo"><!-- 實體類所在的包 --><class name="Employee" table="emp"><id name="empno" column="empno" length="32"> <!-- 主鍵--><generator class="native"></generator></id><property name="empname" length="32"></property><!-- 映射多對一的關系 --><many-to-one name="dept" class="Dept" column="depno" cascade="all"></many-to-one ></class><sql-query name="emp name"> <!-- 配置命名查詢 --><![CDATA[ select e from Employee e where e. empname = :name]]><return alias="" class=" com.java.vo. Employee " /><!--返回類型 這里返回的是Employees類對象--></sql-query><sql-query name="emp for dept"> <!-- 命名查詢 --><![CDATA[ select e from Employee e where e.dept.name = :name]]><return alias="" class=" com.java.vo. Employee " /><!--返回類型--></sql-query></hibernate-mapping>
12.4 本章小結Hibernate使數據持久層以面向對象的方式編程,直接存儲、操作Java對象,使用HQL查詢數據。
|
新聞熱點
疑難解答