JPA支持兩種表達查詢的方法來檢索實體和來自數據庫的其餘持久化數據:查詢語句(Java Persistence Query Language,JPQL)和條件API(criteria API)。JPQL是獨立於數據庫的查詢語句,其用於操做邏輯上的實體模型而非物理的數據模型。條件API是根據實體模型構建查詢條件java
1.Java持久化查詢語句入門 List persons= entityManager.createQuery("select p from Person p").getResultList();數據庫
1.這個查詢語句相似於SQL。但它與真正的SQL的區別是,它不是從一個表中進行選擇查詢,而是指定來自應用程序域模型的實體。 2.查詢select子句也只是列出了查詢實體的別名,若是隻查詢某一列的,可使用點(.)操做符進行來導航實體屬性。以下所示: List persons= entityManager.createQuery("select p.firstName from Person p").getResultList();app
1.1.篩選條件 像SQL同樣,JPQL也支持where子句,用於對搜索的條件過濾。包括大多數的操做符,如:in,between、like以及函數表達式substring、length等等 List persons = entityManager.createQuery("select p from Person p where p.age>23").getResultList();函數
1.2.投影結果 對於查詢的數據量比較大的話,可使用投影的方式,只查詢出有用的列。 //投影 List persons = entityManager.createQuery("select p.firstName,p.age from Person p").getResultList();工具
1.3.聚合查詢 JPQL的聚合查詢語法相似於SQL。例如count List count=entityManager.createQuery("select count(p) from Person p").getResultList();hibernate
1.4.查詢參數 JPQL支持兩種類型的參數綁定語法。對象
1.位置參數表示法接口
其中參數是在查詢字符串中指示,該字符串是在一個問號(?)以後緊隨參數的編號。當執行查詢的時候,開發人員指定應該替換的參數編ip
Query query=entityManager.createQuery("select p from Person p where p.age=?1 and p.firstName=?2"); query.setParameter(1,21); query.setParameter(2,"Jack");開發
2.命名參數表示法
經過在一個冒號(:)以後緊隨參數名稱,在查詢字符串對它進行指示,當執行查詢的時候,開發人員指定應該替換的參數名稱
Query query=entityManager.createQuery("select p from Person p where p.age=:age and p.firstName=:name"); query.setParameter("age",21); query.setParameter("name","Jack");
2.定義查詢 JPA提供Query和TypedQuery(JPA 2.0引入)接口來配置和執行查詢。Query的返回的Object類型,而TypedQuery返回的是指定的Class類型。 //未指定類型,返回Object類型 Query q = entityManager.createQuery("select p from Person p"); //指定返回類型爲Person類型 TypedQuery q1 = entityManager.createQuery("select p from Person p", Person.class);
2.1.動態查詢定義 JPA查詢引擎,能夠將JPQL字符串解析成語法樹,獲取表達式中的實體對象-關係映射的元數據,而後生成等價的SQL。故有兩種方式進行動態查詢。
1.拼接字符串方式
Tip:會引發SQL注入問題
/**
//調用 Query query = entityManager.createQuery(queryPersonJPQL("jack", 21));
2.動態參數化構建查詢條件(推薦使用)
/**
Query query = entityManager.createQuery(queryPersonJPQLByParams()); query.setParameter("name", "Jack"); query.setParameter("age", 21);
2.2.命名查詢定義 命名查詢是一個強大的工具。使用@NamedQuery註解定義一個命名查詢,能夠把它放在任何實體的類定義之上。該註解定義了查詢的名稱,及其查詢的文本。
Tip:命名查詢通暢放置在對應查詢結果的實體類上
@Entity @NamedQuery(name = "findByAge", query = "select p from Person p where p.age=:age") public class Person { //省略 }
Tip:NamedQuery裏面定義的名稱在整個持久化單元中須要惟一,否則運行會出錯。
eg: Exception in thread "main" org.hibernate.DuplicateMappingException: Duplicate query mapping findByAge at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.checkQueryName
調用
List people = entityManager.createNamedQuery("findByAge", Person.class).setParameter("age", 21).getResultList();
若是一個類定義兩個或者以上個的命名查詢,那麼必須把它放置在@NamedQueries()
2.3.綁定參數 經過前面的例子,咱們能夠看到綁定參數有兩種方式:1.位置參數化綁定。2.命名參數化綁定。都是經過Query接口的setParameter方法進行綁定。
1.位置參數化
TypedQuery setParameter(int position, Object value);
2.命名參數化
TypedQuery setParameter(String name, Object value);
第一種位置參數化綁定,若是位置發生變化都須要改變綁定的代碼。推薦使用第二種。
2.4.執行查詢 Query接口與TypedQuery接口提供了三種不一樣的方式執行查詢。
1.executeUpdate
用來執行批量更新或者刪除
2.getSingleResult
獲取單個結果集。若是沒有獲取到數據,則會拋出NoResultException異常。若是獲取多條數據的話,則會拋出NonUniqueResultException異常
3.getResultList
獲取對應的結果集合,指定順序的集合,須要使用List做爲返回值類型。若是沒有獲取到數據的話,則返回一個空集合,不會拋出異常
2.5.分頁 經過setFirstResult() 和setMaxResults() 方法能夠完成分頁的查詢
查詢頁碼爲0,每頁展現2條數據
List people = entityManager.createQuery("select p from Person p ", Person.class).setFirstResult(0).setMaxResults(2).getResultList();
Tip:不能用於經過集合關係鏈接的查詢,由於這些查詢可能返回重複的值。
2.6.查詢超時 若是一個應用程序須要設置查詢響應時間的限制,那麼能夠在查詢中設置javax.persistence.query.timeout屬性(jpa 2.0引入)或者將它做爲持久化屬性的一部分。此屬性定義了查詢在終止前容許容許運行的==毫秒數==。若是查詢超時的時候,會拋出QueryTimeoutException。
TypedQuery query = entityManager.createQuery("select p from Person p", Person.class);
//單位爲毫秒 javax.persistence.query.timeout query.setHint("javax.persistence.query.timeout", 5000); List people = query.getResultList();
2.7.批量更新和刪除 批量更新實體是經過update語句完成。批量刪除實體是經過delete語句完成。二者皆指定的是實體及其類的屬性。
entityManager.getTransaction().begin(); Query query = entityManager.createQuery("update Person p set p.firstName=:name where p.id=:id"); query.setParameter("name", "xiaobai"); query.setParameter("id", 2); query.executeUpdate();
Query query1 = entityManager.createQuery("delete Person p where p.id=:id"); query1.setParameter("id", 9); query1.executeUpdate(); entityManager.getTransaction().commit();
3.使用JPQL查詢的建議 在應用系統中,一般使用查詢的次數要比增長、修改、刪除要多。故合理的使用查詢顯的尤其重要。
1.建議採用命名查詢(NamedQuery)
持久化提供的程序一般會採用預編譯的方式將命名查詢做爲程序初始化階段的一部分。這樣就避免了連續解析JPQL和生成SQL的系統開銷。
2.大數量優先使用投影方式檢索少許的列
jpa查詢一般返回的是整個實體的全部列,可是對於龐大的數據量而言,並非全部的實體列都須要用到。那麼咱們可使用投影的方式來處理。
List<List<Object[]>> persons = entityManager.createQuery("select new List(firstName,age) from Person p").getResultList(); for (Object o : persons) { System.out.println(o); }
//輸出結果
[Jack, 21]
[Jack, 21]
[Jack, 21]
[lily, 19]
[tom, 23]
[tom, 23]