1. 程式人生 > 實用技巧 >Spring JPA 查詢建立

Spring JPA 查詢建立

Spring JPA 查詢建立

這是JPA內容的核心部分,可以收藏用作參閱文件。

1. 查詢轉化和關鍵字

例:一個JPA查詢的轉化

public interface UserRepository extends Repository<User, Long> {

  List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}

我們使用JPA 標準API建立一個查詢,但從本質上講,這將轉換為以下查詢:select u from User u where u.emailAddress = ?1 and u.lastname = ?2

,Spring Data JPA執行屬性檢查並遍歷巢狀屬性,如屬性表示式中所述。

下表描述了JPA支援的關鍵字,以及包含該關鍵字的方法可以轉換成什麼查詢語句:

表:查詢關鍵字及對應查詢語句

關鍵字 樣例 JPQL片段(轉化的查詢語句)
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname
,findByFirstnameIs,findByFirstnameEquals
… where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (引數繫結附加 %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (引數繫結附加 %)
Containing findByFirstnameContaining … where x.firstname like ?1 (引數繫結附加 %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

InNotIn也接受集合的任何子類以及陣列作為一個引數或可變引數。對於相同邏輯運算子的其他語法版本,請檢查儲存庫查詢關鍵字。

2. 使用@Query 自定義查詢

​ 使用自命名查詢宣告實體的查詢是一種有效的方法,該方法適用於少量查詢。由於查詢本身繫結到執行它們的Java方法上,實際上可以通過使用Spring Data JPA @Query註釋直接繫結,而不用將它們註釋到域類。這將域類從特定於永續性的資訊中解放出來,並將查詢合併到該儲存庫介面:

​ 註釋@Query查詢優先於使用@NamedQuery定義的查詢和在orm.xml中宣告的自命名查詢。

例:使用@Query在查詢方法上宣告查詢

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.emailAddress = ?1")
  User findByEmailAddress(String emailAddress);
}

3. 使用高階LIKE表示式

​ 使用@Query建立的自命名查詢的查詢執行機制允許在查詢定義中定義高階LIKE表示式,如下面的示例所示:

例:@Query中定義的LIKE表示式

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname like %?1")
  List<User> findByFirstnameEndsWith(String firstname);
}

​ 在前面的示例中,識別了LIKE的分隔符字元(%),並將查詢轉換為有效的JPQL查詢(移除%)。在執行查詢時,傳遞給方法呼叫的引數將使用之前識別的LIKE模式進行擴充。

4. 使用原生查詢

​ 將nativeQuery標誌設定為true, @Query註釋允許執行原生查詢,如下面的示例所示:

例:使用@Query在查詢方法上宣告一個原生查詢

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
  User findByEmailAddress(String emailAddress);
}

Spring Data JPA目前不支援原生查詢的動態排序,因為它必須操作宣告的實際查詢,而這對本地SQL來說是不可靠的。但是,您可以通過自己指定count查詢來對本機查詢的結果進行分頁,如下面的示例所示:

例:通過使用@Query在查詢方法上宣告用於分頁的本機計數查詢

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

5.使用Sort

​ 我們可以通過PageRequestSort直接完成排序,SortOrder例項中實際使用的屬性需要與您的域模型(持久化模型)匹配。這意味著它們需要解析為查詢中使用的屬性或別名。JPQL將其定義為狀態欄位路徑表示式。

使用任何不可引用的路徑表示式都會導致異常。

​ 但是,使用Sort@Query可以讓您插入包含Order BY子句在內的函式非路徑檢查的Order例項,您可以使用JpaSort。新增可能不安全的排序。

例:使用SortJpaSort

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.lastname like ?1%")
  List<User> findByAndSort(String lastname, Sort sort);

  @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
  List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
}

repo.findByAndSort("lannister", new Sort("firstname"));               //在域模型中指向屬性的有效排序表示式
repo.findByAndSort("stark", new Sort("LENGTH(firstname)"));           //包含函式呼叫的無效排序。Thows 異常
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); //包含顯式不安全順序的有效排序。
repo.findByAsArrayAndSort("bolton", new Sort("fn_len"));              //指向別名函式的有效排序表示式。

6.使用(自)命名引數

​ 預設情況下,Spring Data JPA使用基於位置的引數繫結,如上面的所有示例所述,即引數和?的位置一一順序對應。這使得查詢方法在重構引數位置時容易出錯。要解決這個問題,可以使用@Param註釋為方法引數提供一個具體名稱,並在查詢中繫結該名稱,如下面的示例所示:

例:使用命名引數

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
  User findByLastnameOrFirstname(@Param("lastname") String lastname,
                                 @Param("firstname") String firstname);
}

這樣子就不需要再保證位置的一一對應了,只需要保證名稱的對應即可,方法引數根據它們在定義的查詢中的順序進行切換

參考文件

1.翻譯:【JPA Query Methods】