JPA之使用JPQL語句進行增刪改查
JPA支持兩種表達查詢的方法來檢索實體和來自數(shù)據(jù)庫的其他持久化數(shù)據(jù):查詢語句(Java Persistence Query Language,JPQL)和條件API(criteria API)。JPQL是獨立于數(shù)據(jù)庫的查詢語句,其用于操作邏輯上的實體模型而非物理的數(shù)據(jù)模型。條件API是根據(jù)實體模型構(gòu)建查詢條件
1.Java持久化查詢語句入門
1.這個查詢語句類似于SQL。但它與真正的SQL的區(qū)別是,它不是從一個表中進行選擇查詢,而是指定來自應(yīng)用程序域模型的實體。
2.查詢select子句也只是列出了查詢實體的別名,如果只查詢某一列的,可以使用點(.)操作符進行來導(dǎo)航實體屬性。如下所示:
1.1.篩選條件
像SQL一樣,JPQL也支持where子句,用于對搜索的條件過濾。包括大多數(shù)的操作符,如:in,between、like以及函數(shù)表達式substring、length等等
1.2.投影結(jié)果
對于查詢的數(shù)據(jù)量比較大的話,可以使用投影的方式,只查詢出有用的列。
1.3.聚合查詢
JPQL的聚合查詢語法類似于SQL。例如count
1.4.查詢參數(shù)
JPQL支持兩種類型的參數(shù)綁定語法。
1.位置參數(shù)表示法
其中參數(shù)是在查詢字符串中指示,該字符串是在一個問號(?)之后緊隨參數(shù)的編號。當(dāng)執(zhí)行查詢的時候,開發(fā)人員指定應(yīng)該替換的參數(shù)編
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.命名參數(shù)表示法
通過在一個冒號(:)之后緊隨參數(shù)名稱,在查詢字符串對它進行指示,當(dāng)執(zhí)行查詢的時候,開發(fā)人員指定應(yīng)該替換的參數(shù)名稱
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引入)接口來配置和執(zhí)行查詢。Query的返回的Object類型,而TypedQuery返回的是指定的Class類型。
//未指定類型,返回Object類型 Query q = entityManager.createQuery("select p from Person p"); //指定返回類型為Person類型 TypedQuery<Person> q1 = entityManager.createQuery("select p from Person p", Person.class);
2.1.動態(tài)查詢定義
JPA查詢引擎,可以將JPQL字符串解析成語法樹,獲取表達式中的實體對象-關(guān)系映射的元數(shù)據(jù),然后生成等價的SQL。故有兩種方式進行動態(tài)查詢。
1.拼接字符串方式
Tip:會引起SQL注入問題
/** * 動態(tài)拼接字符串構(gòu)建查詢條件 * * @param name * @param age * @return */ public static String queryPersonJPQL(String name, int age) { String queryQL = "select p from Person p where p.firstName= '" + name + "' and p.age=" + age; return queryQL; } //調(diào)用 Query query = entityManager.createQuery(queryPersonJPQL("jack", 21));
2.動態(tài)參數(shù)化構(gòu)建查詢條件(推薦使用)
/** * 動態(tài)參數(shù)化構(gòu)建查詢條件 * * @return */ public static String queryPersonJPQLByParams() { String queryQL = "select p from Person p where p.firstName=:name and p.age=:age"; return queryQL; } Query query = entityManager.createQuery(queryPersonJPQLByParams()); query.setParameter("name", "Jack"); query.setParameter("age", 21);
2.2.命名查詢定義
命名查詢是一個強大的工具。使用@NamedQuery注解定義一個命名查詢,可以把它放在任何實體的類定義之上。該注解定義了查詢的名稱,及其查詢的文本。
Tip:命名查詢通暢放置在對應(yīng)查詢結(jié)果的實體類上
@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
調(diào)用
List<Person> people = entityManager.createNamedQuery("findByAge", Person.class).setParameter("age", 21).getResultList();
如果一個類定義兩個或者以上個的命名查詢,那么必須把它放置在@NamedQueries()
2.3.綁定參數(shù)
通過前面的例子,我們可以看到綁定參數(shù)有兩種方式:1.位置參數(shù)化綁定。2.命名參數(shù)化綁定。都是通過Query接口的setParameter方法進行綁定。
1.位置參數(shù)化
TypedQuery<X> setParameter(int position, Object value);
2.命名參數(shù)化
TypedQuery<X> setParameter(String name, Object value);
第一種位置參數(shù)化綁定,如果位置發(fā)生變化都需要改變綁定的代碼。推薦使用第二種。
2.4.執(zhí)行查詢
Query接口與TypedQuery接口提供了三種不同的方式執(zhí)行查詢。
1.executeUpdate
用來執(zhí)行批量更新或者刪除
2.getSingleResult
獲取單個結(jié)果集。如果沒有獲取到數(shù)據(jù),則會拋出NoResultException異常。如果獲取多條數(shù)據(jù)的話,則會拋出NonUniqueResultException異常
3.getResultList
獲取對應(yīng)的結(jié)果集合,指定順序的集合,需要使用List作為返回值類型。如果沒有獲取到數(shù)據(jù)的話,則返回一個空集合,不會拋出異常
2.5.分頁
通過setFirstResult() 和setMaxResults() 方法可以完成分頁的查詢
查詢頁碼為0,每頁展示2條數(shù)據(jù)
List<Person> people = entityManager.createQuery("select p from Person p ", Person.class).setFirstResult(0).setMaxResults(2).getResultList();
Tip:不能用于通過集合關(guān)系連接的查詢,因為這些查詢可能返回重復(fù)的值。
2.6.查詢超時
如果一個應(yīng)用程序需要設(shè)置查詢響應(yīng)時間的限制,那么可以在查詢中設(shè)置javax.persistence.query.timeout屬性(jpa 2.0引入)或者將它作為持久化屬性的一部分。此屬性定義了查詢在終止前允許允許運行的==毫秒數(shù)==。如果查詢超時的時候,會拋出QueryTimeoutException。
TypedQuery<Person> query = entityManager.createQuery("select p from Person p", Person.class); //單位為毫秒 javax.persistence.query.timeout query.setHint("javax.persistence.query.timeout", 5000); List<Person> 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查詢的建議
在應(yīng)用系統(tǒng)中,通常使用查詢的次數(shù)要比增加、修改、刪除要多。故合理的使用查詢顯的尤為重要。
1.建議采用命名查詢(NamedQuery)
持久化提供的程序通常會采用預(yù)編譯的方式將命名查詢作為程序初始化階段的一部分。這樣就避免了連續(xù)解析JPQL和生成SQL的系統(tǒng)開銷。
2.大數(shù)量優(yōu)先使用投影方式檢索少量的列
jpa查詢通常返回的是整個實體的所有列,但是對于龐大的數(shù)據(jù)量而言,并不是所有的實體列都需要用到。那么我們可以使用投影的方式來處理。
List<List<Object[]>> persons = entityManager.createQuery("select new List(firstName,age) from Person p").getResultList(); for (Object o : persons) { System.out.println(o); } //輸出結(jié)果 [Jack, 21] [Jack, 21] [Jack, 21] [lily, 19] [tom, 23] [tom, 23]
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
WebSocket 中使用 @Autowired 注入對應(yīng)為null的解決方案
SpringBoot集成WebSocket時,會遇到service對象為null的情況,原因是Spring默認(rèn)為單例模式與WebSocket的多對象模式相沖突,當(dāng)客戶端與服務(wù)器端建立連接時,會創(chuàng)建新的WebSocket對象,本文給大家介紹WebSocket 中使用 @Autowired 注入對應(yīng)為null的問題,感興趣的朋友一起看看吧2024-10-10解決rocketmq-client查詢手動發(fā)送消息異常問題
這篇文章主要介紹了解決rocketmq-client查詢手動發(fā)送消息異常問題,具有很好的參考價值,希望對大家大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08SpringBoot啟動異常Exception in thread “main“ 
本文主要介紹了SpringBoot啟動異常Exception in thread “main“ java.lang.UnsupportedClassVersionError,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07SpringCloud_Sleuth分布式鏈路請求跟蹤的示例代碼
Spring Cloud Sleuth是一款針對Spring Cloud的分布式跟蹤工具,本文通過實例代碼介紹了SpringCloud_Sleuth分布式鏈路請求跟蹤,感興趣的朋友跟隨小編一起看看吧2023-02-02