spring-data-JPA repository自定義方法規則


一、自定義方法的規則

Spring Data JPA框架在進行方法名解析時,會先把方法名多余的前綴截取掉,比如find,findBy,read,readBy,get,getBy,然后對剩下的部分進行解析。
假如創建如下的查詢:findByUserDepUuid(),框架在解析該方法時,首先剔除findBy,然后對剩下的屬性進行解析,假設查詢實體為Doc
1:先判斷userDepUuid(根據POJO規范,首字母變為小寫)是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;
2:從右往左截取第一個大寫字母開頭的字符串此處為UUID),然后檢查剩下的字符串是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,則重復第二步,繼續從右往左截取;最后假設用戶為查詢實體的一個屬性;
3:接着處理剩下部分(DepUuid),先判斷用戶所對應的類型是否有depUuid屬性,如果有,則表示該方法最終是根據“Doc.user.depUuid”的取值進行查詢;否則繼續按照步驟2的規則從右往左截取,最終表示根據“Doc.user.dep.uuid”的值進行查詢。
4:可能會存在一種特殊情況,比如Doc包含一個用戶的屬性,也有一個userDep屬性,此時會存在混合。可以明確在屬性之間加上“_”以顯式表達意思,比如“findByUser_DepUuid )“或者”findByUserDep_uuid()"
關鍵詞    樣品    JPQL片段
IsNotNull    findByAgeNotNull    ...其中x.age 不為空【年齡不為空】
喜歡    findByNameLike    ...其中x.name是什么樣的?【模糊查找是......】
不喜歡    findByNameNotLike    ...其中x.name不喜歡?【模糊查找不是......】
從...開始    findByNameStartingWith    ...其中x.name類似?(參數綁定附加%)【模糊匹配,類似使用%結尾】
EndingWith    findByNameEndingWith    ...其中x.name類似於?(參數與預置%綁定)【模糊匹配,類似使用%開始】
含    findByNameContaining    ...其中x.name like?(參數綁定在%中)[模糊匹配,類似使用%開頭和結尾]
排序依據    findByAgeOrderByName    ...其中x.age =?order by x.name desc 【查找后排序】
不    findByNameNot    ...其中x.name <>?【查找列不是...的】
在    findByAgeIn    ...哪里x.age在?
NotIn    findByAgeNotIn    ...其中x.age不在?
真正    findByActiveTrue    ...其中x.avtive = true
產品嫁接    findByActiveFalse    ...其中x.active = false
和     findByNameAndAge    ...其中x.name =?和x.age =?2
要么    findByNameOrAge    ...其中x.name =?或x.age =?2
之間    findBtAgeBetween    ...其中x.age之間?和?2
少於    findByAgeLessThan    ...其中x.age <?
比...更棒    findByAgeGreaterThan    ...其中x.age>?
在那之后    ...    ...
一片空白    findByAgeIsNull    ...其中x.age為空

自定義查找實例:

    /**
     * 根據id查用戶
     **/
    List<User> findByIdOrName(Long id,String name);
 
    /**
     * 根據id查用戶
     **/
    User queryXXXXByName(String name);
 
    /**
     * 根據id查name
     **/
    User readNameById(Long id);
 
    /**
     * 查年齡為10歲的學生
     **/
    List<User> getByAge(int age);

三,Spring Data JPA分頁查詢:

    /**
     * 分頁查詢左右用戶
     * @param pageable
     * @return
     */
    Page<User> findAll(Pageable pageable);
 
    /**
     * 分頁查詢id不是傳入id的用戶
     * @param id
     * @param pageable
     * @return
     */
    Page<User> findByIdNot(Long id,Pageable pageable);

【注意】分頁查詢,的結果頁,,頁接口繼承自切片,這個接口有以下方法

public interface Slice<T> extends Iterable<T> {
    int getNumber();//返回當前頁碼
 
    int getSize();//返回當前頁大小(可能不是一整頁)
 
    int getNumberOfElements();//返回當前的元素數量
 
    List<T> getContent();//返回當前頁的內容(查詢結果)
 
    boolean hasContent();//判斷是否有內容存在
 
    Sort getSort();//返回排序方式
 
    boolean isFirst();//判斷是不是第一頁
 
    boolean isLast();//判斷是不是最后一頁
 
    boolean hasNext();//判斷是否還有下一頁
 
    boolean hasPrevious();//判斷是否上一頁
 
    Pageable nextPageable();//返回下一頁
 
    Pageable previousPageable();//返回上一頁,如果當前已經是第一個,則返回,請求前一個可以是【null】。在調用此方法之前,客戶端應該檢查是否收到一個非值。
 
    <S> Slice<S> map(Converter<? super T, ? extends S> var1);//用給定的映射,映射當前的內容,為Slice
}
方法名    關鍵字    SQL
findById         其中id =?
findByIdIs    是    其中id =?
findByIdEquals    等於    其中id =?
findByNameAndAge    和    where name =?和年齡=?
findByNameOrAge    要么    where name =?或年齡=?
findByNameOrderByAgeDesc    按順序排列    where name =?按年齡順序排列
findByAgeNotIn    不在    年齡不在(?)
findByStatusTrue    真正    where status = true
findByStatusFalse    假    其中status = false
findByAgeBetween    之間    年齡在哪?和?
findByNameNot    不    名稱<>?
findByAgeLessThan    少於    年齡<?
findByAgeLessThanEqual    LessThanEqual    年齡<=?
findByAgeGreaterThan    比...更棒    年齡>?
findByAgeGreaterThanEqual    GreaterThanEqual    年齡> =?
findByAgeAfter    后    年齡>?
findByAgeBefore    之前    年齡<?
findByNameIsNull    一片空白    其中名稱為空
findByNameNotNull    不為空    其中名稱不為空
findByNameLike    喜歡    哪里的名字像?
findByNameNotLike    不喜歡    哪里的名字不像?
findByNameStartingWith    從...開始    名稱如'?%'
findByNameEndingWith    EndingWith    名稱如'%?'
findByNameContaining    含    名稱如'%?%'

代碼中幾個復雜的。 
findByNameAndAgeAndSex:表示where name =?和年齡=?和性=? 
findByNameInAndAgeIsNull:表示(?)中的名稱和年齡為null  
findByNameAndAgeInAndSexIn:表示where name =?年齡(?)和性別(?)

可以看出關鍵字是可以連用的,查找都是用findBy +表中列名,表的列名還有關鍵字等等拼接時,它們的首字母要大寫。  

二、懶加載引起的no-session解決方法之一,沒有頁面只有測試用例沒有效果

 

  懶加載造成JPA提供的findOne方法和save 方法在關聯表查詢和保存時報錯;所以適合單表操作,多表可以通過自定義方法分別執行

   保存和更新需要通過@Query的方法執行

三、@Query注解的使用

1. 一個使用@Query注解的簡單例子

@Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2")
List<Book> findByPriceRange(long price1, long price2);

 

2.  Like表達式

@Query(value = "select name,author,price from Book b where b.name like %:name%")
List<Book> findByNameMatch(@Param("name") String name);

 

3. 使用Native SQL Query

所謂本地查詢,就是使用原生的sql語句(根據數據庫的不同,在sql的語法或結構方面可能有所區別)進行查詢數據庫的操作。

@Query(value = "select * from book b where b.name=?1", nativeQuery = true)
List<Book> findByName(String name);

 

4. 使用@Param注解注入參數

@Query(value = "select name,author,price from Book b where b.name = :name AND b.author=:author AND b.price=:price")
List<Book> findByNamedParam(@Param("name") String name, @Param("author") String author,
        @Param("price") long price);

 

5. SPEL表達式(使用時請參考最后的補充說明)

   '#{#entityName}'值為'Book'對象對應的數據表名稱(book)。

public interface BookQueryRepositoryExample extends Repository<Book, Long>{

       @Query(value = "select * from #{#entityName} b where b.name=?1", nativeQuery = true)
       List<Book> findByName(String name);

}

 

6. 一個較完整的例子

復制代碼
public interface BookQueryRepositoryExample extends Repository<Book, Long> {
    @Query(value = "select * from Book b where b.name=?1", nativeQuery = true) 
    List<Book> findByName(String name);// 此方法sql將會報錯(java.lang.IllegalArgumentException),看出原因了嗎,若沒看出來,請看下一個例子

    @Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2")
    List<Book> findByPriceRange(long price1, long price2);

    @Query(value = "select name,author,price from Book b where b.name like %:name%")
    List<Book> findByNameMatch(@Param("name") String name);

    @Query(value = "select name,author,price from Book b where b.name = :name AND b.author=:author AND b.price=:price")
    List<Book> findByNamedParam(@Param("name") String name, @Param("author") String author,
            @Param("price") long price);

}
復制代碼

 

7.  解釋例6中錯誤的原因:

     因為指定了nativeQuery = true,即使用原生的sql語句查詢;否則表名需為實體類對象。使用java對象'Book'作為表名來查自然是不對的。只需將Book替換為表名book。

@Query(value = "select * from book b where b.name=?1", nativeQuery = true)
List<Book> findByName(String name);
@Param入參有此注解,則sql中用:name接收參數;否則用?1的占位符接收參數且順序也要一致

8.   有同學提出來了,例子5中用'#{#entityName}'為啥取不到值啊?

  先來說一說'#{#entityName}'到底是個啥。從字面來看,'#{#entityName}'不就是實體類的名稱么,對,他就是。

  實體類Book,使用@Entity注解后,spring會將實體類Book納入管理。默認'#{#entityName}'的值就是'Book'。

  但是如果使用了@Entity(name = "book")來注解實體類Book,此時'#{#entityName}'的值就變成了'book'。

  只需要在用@Entity來注解實體類時指定name為此實體類對應的表名。在原生sql語句中,就可以把'#{#entityName}'來作為數據表名使用。

9.  @Modifying注解

    1、在@Query注解中編寫JPQL實現DELETE和UPDATE操作的時候必須加上@modifying注解,以通知Spring Data 這是一個DELETE或UPDATE操作。

    2、UPDATE或者DELETE操作需要使用事務,此時需要 定義Service層,在Service層的方法上添加事務操作。  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM