springjpa合集地址:https://www.jianshu.com/nb/38441578
先看看JpaRepository的繼承樹,從繼承樹可以看出來JapRepository除了繼承了Repository那邊的路線外,還繼承了一個新的接口——QueryByExampleExecutor
QueryByExampleExecutor
很多時候我們的crud項目中有複雜查詢功能,頁面有很多的查詢字段,這些字段都是表結構的某個字段。
QueryByExampleExecutor接口
QueryByExampleExecutor接口能實現較爲簡單的上述功能。
public interface QueryByExampleExecutor<T> {
<S extends T> Optional<S> findOne(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example, Sort sort);
<S extends T> Page<S> findAll(Example<S> example, Pageable pageable);
<S extends T> boolean exists(Example<S> example);
}
我們將關注點放在findAll(Example<S> example)方法上,它接收一個Example實例,這個實例就是查詢條件,它由具體的表對象而來。這個方法的返回值是Iterable對象,需要進行轉換後才能傳遞到前端。
Example接口
Example提供了兩個靜態方法用於將表對象轉換成Example對象
public interface Example<T> {
static <T> Example<T> of(T probe) {
return new TypedExample<>(probe, ExampleMatcher.matching());
}
static <T> Example<T> of(T probe, ExampleMatcher matcher) {
return new TypedExample<>(probe, matcher);
}
//省略...
}
1. of(T probe)
//舉個例子,我們要查詢用戶中年齡等於12,城市在南京,姓名等於張三的用戶。
User user=new User();
user.setAge(12);
user.setCity("南京");
user.setName("張三");
Example example=Example.of(user);
Iterable<User> users=userRepository.findAll(example);
第一種是精確值查詢,所有不爲null的字段(空字符串不算null)都會作爲條件進行查詢。
2. of(probe,match)
第二種和第一種的區別就是多了一個ExampleMatcher,它是一個匹配器,用於表示具體怎麼匹配。它可以對字符串條件做處理,例如模糊查詢。注意非字符串條件無法做處理,只能精確查詢。
//例如,我們要查詢姓張的用戶---> name like '張%'
User user=new User();
user.setName("張");
//創建一個匹配器,並設置姓名只要以給的條件開始就可以,不需要精確查詢
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.startsWith())
Example example=Example.of(user,matcher);
Iterable<User> users=userRepository.findAll(example);
ExampleMatcher接口
public interface ExampleMatcher {
static ExampleMatcher matching() {
return matchingAll();
}
static ExampleMatcher matchingAny() {
return new TypedExampleMatcher().withMode(MatchMode.ANY);
}
static ExampleMatcher matchingAll() {
return new TypedExampleMatcher().withMode(MatchMode.ALL);
}
//...
}
ExampleMatcher接口提供了三個靜態方法用於創建一個匹配器,觀察這三個方法,其實區別就是any和all的區別。
any指的是所有的條件只要有一個滿足就篩選出來。---> where age=12 or city='南京' or name like '張三%'。
all指的是所有的條件都滿足才篩選出來。---> where age=12 and city='南京' and name like '張三%'。
創建完實例以後我們可以採用鏈式編程的方式追加規則。例如
ExampleMatcher matcher = ExampleMatcher.matching()
//where name like 'XXX%'
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.startsWith())
//where name like '%XXX'
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.endsWith())
//where name like '%XXX%'
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
//name忽略大小寫
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.ignoreCase())
//name大小寫敏感,不忽略大小寫,默認
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.caseSensitive())、
//name正則查詢
.withMatcher("name", ExampleMatcher.GenericPropertyMatchers.regex())
//忽略id和age條件,即使id和age不爲空也不作爲查詢條件
.withIgnorePaths("id", "age")
//忽略大小寫
.withIgnoreCase("name","city")
//忽略null值條件(默認)
.withIgnoreNullValues()
//不忽略null值條件,如果條件爲null,那麼就按照is null查詢
.withIncludeNullValues();
JpaRepository
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
除了繼承的PagingAndSortingRepository和QueryByExampleExecutor接口外,還增加了一些新的方法,例如皮批量增加刪除之類。繼承JpaRepository以後findAll方法返回的是List,不用再轉換了