1. 程式人生 > >spring boot jpa之 從方法名建立查詢

spring boot jpa之 從方法名建立查詢

Repository是總介面,CrudRepository繼承它,PagingAndSortingRepository又繼承CrudRepository   ,
JpaRepository繼承PagingAndSortingRepository
dao層例如定義了 UserRepository  extends JpaRepository<User,Long>{

              //........這裡面就是查詢方法,可以按方法名字來定義,或者命名式查詢、按示例查詢、@Query查詢等

}

想知道他們中的api可以引入jar包原始碼,點進去檢視;專案中dao層定義的介面繼承JpaRepository或者PagingAndSortingRepository;
dao層上自定義的介面不用使用 @Repository ,只需要在資料來源的配置@Configuration 裡指定dao層的路徑即可,spring boot自動會把資料來源注入到dao層來例項化 ;@NoRepositoryBean只加在中間的過度介面中,這中介面不用例項化;MyBaseRepository的作用就是有選擇地暴露CRUD方法;

定義查詢方法:

這裡先說按方法名字來定義查詢方法

 按照規範建立查詢方法,一般按照java駝峰式書寫規範加一些特定關鍵字,例如我們想通過任務名來獲取任務實體類列表

利用屬性獲取任務列表

1

2

3

interface TaskDao extends MyBaseRepository<Task, Long> {

  List<Task> findByName(String name);

}

 利用and 和 or來獲取任務列表

1

2

3

4

interface TaskDao extends JpaRepository<Task, Long> {

  List<Task> findByNameAndProjectId(String name,Long projectId);

  List<Task> findByNameOrProjectId(String name,Long projectId);

}

 利用Pageable ,Sort,Slice獲取分頁的任務列表和排序

1

2

3

4

5

interface TaskDao extends JpaRepository<Task, Long> {

  Page<Task> findByName(String name,Pageable pageable);

  Slice<Task> findByName(String name, Pageable pageable);

  List<Task> findByName(String name, Sort sort);

}

 利用Distinct去重

1

2

3

interface TaskDao extends JpaRepository<Task, Long> {

    List<Person> findDistinctTaskByNameOrProjectId(String name, Long projectId);

}

 利用OrderBy進行排序

1

2

3

interface TaskDao extends JpaRepository<Task, Long> {

    List<Person> findByNameOrderByProjectIdDesc(String name, Long projectId);

}

 利用 Top 和 First來獲取限制資料

1

2

3

4

5

6

7

8

9

10

11

12

13

interface TaskDao extends JpaRepository<Task, Long> {

    User findFirstByOrderByLastnameAsc();

 

Task findTopByOrderByNameDesc(String name);

 

Page<Task> queryFirst10ByName(String name, Pageable pageable);

 

Slice<Task> findTop3ByName(String name, Pageable pageable);

 

List<Task> findFirst10ByName(String name, Sort sort);

 

List<Task> findTop10ByName(String name, Pageable pageable);

}

 

那麼spring data jpa是怎麼通過這些規範來進行組裝成查詢語句呢?

Spring Data JPA框架在進行方法名解析時,會先把方法名多餘的字首擷取掉,比如 find、findBy、read、readBy、get、getBy,然後對剩下部分進行解析。

假如建立如下的查詢:findByTaskProjectName(),框架在解析該方法時,首先剔除 findBy,然後對剩下的屬性進行解析,假設查詢實體為Doc

  1. 先判斷 taskProjectName (根據 POJO 規範,首字母變為小寫)是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;

  2. 從右往左擷取第一個大寫字母開頭的字串此處為Name),然後檢查剩下的字串是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,則重複第二步,繼續從右往左擷取;最後假設task為查詢實體Person的一個屬性;

  3. 接著處理剩下部分(ProjectName),先判斷 task 所對應的型別是否有projectName屬性,如果有,則表示該方法最終是根據 “ Person.task.projectName”的取值進行查詢;否則繼續按照步驟 2 的規則從右往左擷取,最終表示根據 “Person.task.project.name” 的值進行查詢。

  4. 可能會存在一種特殊情況,比如 Person包含一個 task 的屬性,也有一個 projectName 屬性,此時會存在混淆。可以明確在屬性之間加上 “_” 以顯式表達意圖,比如 “findByTask_ProjectName()”

支援的規範表示式,這裡以實體為User,有firstName和lastName,age

表示式 例子 hql查詢語句
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEqual … 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 findByAgeIsNull … 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 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … 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)

發現這些查詢都是隻針對單表進行查詢,如果是多表的複雜查詢,還有分頁該怎麼查,下次再研究看看…