JPA的Repository詳解
Spring Data JPA
Spring Data是Spring提供的操作數據的框架,Spring Data JPA是Spring Data的一個模塊,通過Spring data 基於jpa標准操作數據的模塊。
Spring Data的核心能力,就是基於JPA操作數據,並且可以簡化操作持久層的代碼。
它使用一個叫作Repository的接口類為基礎,它被定義為訪問底層數據模型的超級接口。而對於某種具體的數據訪問操作,則在其子接口中定義。
Spring Data可以讓我們只定義接口,只要遵循spring data的規范,就無需寫實現類,不用寫sql語句直接查詢數據。
Repository
- Repository
提供了findBy + 屬性 方法- CrudRepository
繼承了Repository 提供了對數據的增刪改查- PagingAndSortRepository:
繼承了CrudRepository 提供了對數據的分頁和排序,缺點是只能對所有的數據進行分頁或者排序,不能做條件判斷- JpaRepository: 繼承了PagingAndSortRepository
開發中經常使用的接口,主要繼承了PagingAndSortRepository,對返回值類型做了適配
- JpaRepository: 繼承了PagingAndSortRepository
- PagingAndSortRepository:
- CrudRepository
- JpaSpecificationExecutor
提供多條件查詢
CrudRepository
CrudRepository繼承Repository,添加了一組對數據的增刪改查的方法
PagingAndSortingRepository
PagingAndSortingRepository繼承CrudRepository,添加了一組分頁排序相關的方法
JpaRepository
JpaRepository繼承PagingAndSortingRepository,添加了一組JPA規范相關的方法。對繼承父接口中方法的返回值進行了適配,因為在父類接口中通常都返回迭代器,需要我們自己進行強制類型轉化。而在JpaRepository中,直接返回了List。
開發中最常用JpaRepository
JpaSpecificationExecutor
這個接口比較特殊,單獨存在,沒有繼承以上接口。主要提供了多條件查詢的支持,並且可以在查詢中添加分頁和排序。因為這個接口單獨存在,因此需要配合以上說的接口使用。
JpaRepository查詢功能
Jpa方法命名規則
JpaRepository支持接口規范方法名查詢。意思是如果在接口中定義的查詢方法符合它的命名規則,就可以不用寫實現,目前支持的關鍵字如下。
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Is,Equals | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEquals | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEquals | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like ‘?%’ |
EndingWith | findByNameEndingWith | where name like ‘%?’ |
Containing | findByNameContaining | where name like ‘%?%’ |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection<?> c) | where id in (?) |
NotIn | findByIdNotIn(Collection<?> c) | where id not in (?) |
True | findByAaaTue | where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
top | findTop10 | top 10/where ROWNUM <=10 |
使用方法
使用時自定義接口繼承JpaRepository,傳入泛型,第一個參數為要操作的實體類,第二個參數為該實體類的主鍵類型
public interface SpuRepository extends JpaRepository<Spu, Long> {
Spu findOneById(Long id);
Page<span class="token generics function"><span class="token punctuation"><</span>Spu<span class="token punctuation">></span></span> <span class="token function">findByCategoryIdOrderByCreateTimeDesc</span><span class="token punctuation">(</span>Long cid<span class="token punctuation">,</span> Pageable pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>
Page<span class="token generics function"><span class="token punctuation"><</span>Spu<span class="token punctuation">></span></span> <span class="token function">findByRootCategoryIdOrderByCreateTime</span><span class="token punctuation">(</span>Long cid<span class="token punctuation">,</span> Pageable pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解析過程
1. Spring Data JPA框架在進行方法名解析時,會先把方法名多余的前綴截取掉,比如find,findBy,read,readBy,get,getBy,然后對剩下的部分進行解析。
2. 假設創建如下查詢findByCategoryId(),框架在解析該方法時,首先剔除findBy,然后對剩下的屬性進行解析,假設查詢實體為Spu
(1)先判斷categoryId(根據POJO 規范,首字母變為小寫)是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;
(2)從右往左截取第一個大寫字母開頭的字符串此處為Id),然后檢查剩下的字符串是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;
如果沒有該屬性,則重復第二步,繼續從右往左截取;最后假設user為查詢實體的一個屬性;
(3)接着處理剩下部分(CategoryId),先判斷用戶所對應的類型是否有categoryId屬性,如果有,則表示該方法最終是根據"Spu.categoryId"的取值進行查詢;
否則繼續按照步驟2的規則從右往左截取。
(4)可能會存在一種特殊情況,比如Spu包含一個categoryId 的屬性,也有一個 rootCategoryId屬
性,此時會存在混淆。可以明確在屬性之間加上"_" 以顯式表達意圖,比如
"findByRoot_CategoryId()"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
3. 特殊參數
可以直接在方法的參數上加入分頁或排序的參數,比如:
Page<Spu> findByCategoryId(Long cid, Pageable pageable);
List<Spu> findByCategoryId(Long cid, Sort sort);
- 1
- 2
- 3
4. JPA的@NamedQueries
(1)1:在實體類上使用@NamedQuery
@NamedQuery(name = "Spu.findByRootCategoryId",query = "select s from Spu s where s.rootCategoryId >= ?1")
(2)在自己實現的DAO的Repository接口里面定義一個同名的方法,示例如下:
public List<Spu> findByRootCategoryId(Long rootCategoryId);
(3)然后Spring會先找是否有同名的NamedQuery,如果有,那么就不會按照接口定義的方法來解析。
- 1
- 2
- 3
- 4
- 5
5. 使用@Query
在方法上標注@Query來指定本地查詢
參數nativeQuery默認為false,nativeQuery=false時,value參數寫的是JPQL,JPQL是用來操作model對象的
@Query(value="select s from Spu s where s.title like %?1" )
public List<Spu> findByTitle(String title);
- 1
- 2
nativeQuery=true時,value參數寫的是原生sql
@Query(value="select * from spu s where s.title like %?1",nativeQuery=true )
public List<Spu> findByTitle(String title);
- 1
- 2
6. 使用@Param命名化參數
@Query(value = "select s from Spu s where s.title in (:titles)")
List<Spu> findByTitle(@Param("titles") List<String> titles);
- 1
- 2
參考文章:
JpaRepository數據層
Spring Data JPA 提供的各種Repository接口
spring data jpa方法命名規則
一步一步學SpringDataJpa——JpaRepository查詢功能