一、自定義方法的規則
關鍵詞 樣品 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層的方法上添加事務操作。