基于JPA的Repository使用詳解
Spring Data JPA
Spring Data是Spring提供的操作數(shù)據(jù)的框架,Spring Data JPA是Spring Data的一個(gè)模塊,通過Spring data 基于jpa標(biāo)準(zhǔn)操作數(shù)據(jù)的模塊。
Spring Data的核心能力,就是基于JPA操作數(shù)據(jù),并且可以簡化操作持久層的代碼。
它使用一個(gè)叫作Repository的接口類為基礎(chǔ),它被定義為訪問底層數(shù)據(jù)模型的超級接口。而對于某種具體的數(shù)據(jù)訪問操作,則在其子接口中定義。
Spring Data可以讓我們只定義接口,只要遵循spring data的規(guī)范,就無需寫實(shí)現(xiàn)類,不用寫sql語句直接查詢數(shù)據(jù)。
Repository
Repository
提供了findBy + 屬性 方法
CrudRepository
繼承了Repository 提供了對數(shù)據(jù)的增刪改查
PagingAndSortRepository
繼承了CrudRepository 提供了對數(shù)據(jù)的分頁和排序,缺點(diǎn)是只能對所有的數(shù)據(jù)進(jìn)行分頁或者排序,不能做條件判斷
JpaRepository
: 繼承了PagingAndSortRepository
開發(fā)中經(jīng)常使用的接口,主要繼承了PagingAndSortRepository,對返回值類型做了適配
JpaSpecificationExecutor
提供多條件查詢
CrudRepository
CrudRepository繼承Repository,添加了一組對數(shù)據(jù)的增刪改查的方法
PagingAndSortingRepository
PagingAndSortingRepository繼承CrudRepository,添加了一組分頁排序相關(guān)的方法
JpaRepository
JpaRepository繼承PagingAndSortingRepository,添加了一組JPA規(guī)范相關(guān)的方法。對繼承父接口中方法的返回值進(jìn)行了適配,因?yàn)樵诟割惤涌谥型ǔ6挤祷氐?,需要我們自己進(jìn)行強(qiáng)制類型轉(zhuǎn)化。而在JpaRepository中,直接返回了List。
開發(fā)中最常用JpaRepository
JpaSpecificationExecutor
這個(gè)接口比較特殊,單獨(dú)存在,沒有繼承以上接口。主要提供了多條件查詢的支持,并且可以在查詢中添加分頁和排序。因?yàn)檫@個(gè)接口單獨(dú)存在,因此需要配合以上說的接口使用。
JpaRepository查詢功能
Jpa方法命名規(guī)則
JpaRepository支持接口規(guī)范方法名查詢。意思是如果在接口中定義的查詢方法符合它的命名規(guī)則,就可以不用寫實(shí)現(xiàn),目前支持的關(guān)鍵字如下。
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 |
使用方法
使用時(shí)自定義接口繼承JpaRepository,傳入泛型,第一個(gè)參數(shù)為要操作的實(shí)體類,第二個(gè)參數(shù)為該實(shí)體類的主鍵類型
public interface SpuRepository extends JpaRepository<Spu, Long> { Spu findOneById(Long id); Page<Spu> findByCategoryIdOrderByCreateTimeDesc(Long cid, Pageable pageable); Page<Spu> findByRootCategoryIdOrderByCreateTime(Long cid, Pageable pageable); }
解析過程
1. Spring Data JPA框架在進(jìn)行方法名解析時(shí)
會先把方法名多余的前綴截取掉,比如find,findBy,read,readBy,get,getBy,然后對剩下的部分進(jìn)行解析。
2. 假設(shè)創(chuàng)建如下查詢findByCategoryId()
框架在解析該方法時(shí),首先剔除findBy,然后對剩下的屬性進(jìn)行解析,假設(shè)查詢實(shí)體為Spu
(1) 先判斷categoryId(根據(jù)POJO 規(guī)范,首字母變?yōu)樾懀┦欠駷椴樵儗?shí)體的一個(gè)屬性,如果是,則表示根據(jù)該屬性進(jìn)行查詢;如果沒有該屬性,繼續(xù)第二步;
(2) 從右往左截取第一個(gè)大寫字母開頭的字符串此處為Id),然后檢查剩下的字符串是否為查詢實(shí)體的一個(gè)屬性,如果是,則表示根據(jù)該屬性進(jìn)行查詢;
如果沒有該屬性,則重復(fù)第二步,繼續(xù)從右往左截??;最后假設(shè)user為查詢實(shí)體的一個(gè)屬性;
(3) 接著處理剩下部分(CategoryId),先判斷用戶所對應(yīng)的類型是否有categoryId屬性,如果有,則表示該方法最終是根據(jù)"Spu.categoryId"的取值進(jìn)行查詢;
否則繼續(xù)按照步驟2的規(guī)則從右往左截取。
(4) 可能會存在一種特殊情況,比如Spu包含一個(gè)categoryId 的屬性,也有一個(gè) rootCategoryId屬性,此時(shí)會存在混淆??梢悦鞔_在屬性之間加上"_" 以顯式表達(dá)意圖,比如 "findByRoot_CategoryId()"
3. 特殊參數(shù)
可以直接在方法的參數(shù)上加入分頁或排序的參數(shù),比如:
Page<Spu> findByCategoryId(Long cid, Pageable pageable); List<Spu> findByCategoryId(Long cid, Sort sort);
4. JPA的@NamedQueries
(1) 在實(shí)體類上使用@NamedQuery
@NamedQuery(name = "Spu.findByRootCategoryId",query = "select s from Spu s where s.rootCategoryId >= ?1")
(2) 在自己實(shí)現(xiàn)的DAO的Repository接口里面定義一個(gè)同名的方法,示例如下:
public List<Spu> findByRootCategoryId(Long rootCategoryId);
(3) 然后Spring會先找是否有同名的NamedQuery,如果有,那么就不會按照接口定義的方法來解析。
5. 使用@Query
在方法上標(biāo)注@Query來指定本地查詢
參數(shù)nativeQuery默認(rèn)為false,nativeQuery=false時(shí),value參數(shù)寫的是JPQL,JPQL是用來操作model對象的
@Query(value="select s from Spu s where s.title like %?1" ) public List<Spu> findByTitle(String title);
nativeQuery=true時(shí),value參數(shù)寫的是原生sql
@Query(value="select * from spu s where s.title like %?1",nativeQuery=true ) public List<Spu> findByTitle(String title);
6. 使用@Param命名化參數(shù)
@Query(value = "select s from Spu s where s.title in (:titles)") List<Spu> findByTitle(@Param("titles") List<String> titles);
JPA自定義Repository方法
如果不使用SpringData的方法,想要自己實(shí)現(xiàn),該怎么辦呢?
定義一個(gè)接口:聲明要添加的, 并自實(shí)現(xiàn)的方法
提供該接口的實(shí)現(xiàn)類:類名需在要聲明的 Repository 后添加 Impl, 并實(shí)現(xiàn)方法
聲明 Repository 接口, 并繼承 1) 聲明的接口
注意:默認(rèn)情況下, Spring Data 會在 base-package 中查找 "接口名Impl" 作為實(shí)現(xiàn)類. 也可以通過 repository-impl-postfix 聲明后綴.
這張圖是類與接口之間的關(guān)系
下面是具體的實(shí)現(xiàn)
包結(jié)構(gòu)
類與接口之間的關(guān)系代碼
public interface PersonRepositoiry extends JpaRepository<Person, Integer> ,PersonDao{ public interface PersonDao { void test(); } @Repository public class PersonRepositoiryImpl implements PersonDao{ @PersistenceContext private EntityManager em; @Override public void test() { //只是用來測試 Person person = em.find(Person.class, 1); System.out.println(person); } }
測試代碼
@Test public void testCustomerRepositoryMethod() { personRepositoiry.test(); }
經(jīng)過實(shí)踐發(fā)現(xiàn)
XXXRepositoryImpl 與XXXRepository前面的名字必須相同,后面的也需要按照規(guī)則寫
若將XXXRepositoryImpl與XXXRepository接口放在同意包下,XXXRepositoryImpl不需要添加@Repository注解,但是當(dāng)XXXRepositoryImpl與XXXRepository接口不在同一包下,需要在在XXXRepositoryImpl類上加@Repository注解進(jìn)行修飾
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SWT(JFace)體驗(yàn)之圖片的動態(tài)漸變效果
SWT(JFace)體驗(yàn)之圖片的動態(tài)漸變效果2009-06-06Java Jedis NOAUTH Authentication required問題解決方法
這篇文章主要介紹了Java Jedis NOAUTH Authentication required問題解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07Springboot的maven間接依賴的實(shí)現(xiàn)
這篇文章主要介紹了Springboot的maven間接依賴的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05淺談hibernate急迫加載問題(多重外鍵關(guān)聯(lián))
這篇文章主要介紹了淺談hibernate急迫加載問題(多重外鍵關(guān)聯(lián)),具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12詳解Android系統(tǒng)中的root權(quán)限獲得原理
這篇文章主要介紹了詳解Android系統(tǒng)中的Root權(quán)限獲得原理,安卓基于Linux,所以原理也相當(dāng)于Linux中的root用戶,需要的朋友可以參考下2015-08-08Java使用Spring發(fā)送郵件的實(shí)現(xiàn)代碼
本篇文章主要介紹了使用Spring發(fā)送郵件的實(shí)現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03