Spring?Data?JPA系列JpaSpecificationExecutor用法詳解
在上一篇文章中,我們介紹了QueryByExampleExecutor動(dòng)態(tài)查詢(xún)的方法,那么今天我們來(lái)學(xué)習(xí)JpaSpecificationExecutor的詳細(xì)用法。
1、JpaSpecificationExecutor用法
我們來(lái)創(chuàng)建實(shí)體類(lèi),第一步:創(chuàng)建User類(lèi)和UserAddress類(lèi)
// User類(lèi)
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = "address")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String email;
@Enumerated(value = EnumType.STRING)
private SexEnum sex;
private Integer age;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@OneToMany(mappedBy = "user",fetch = FetchType.EAGER)
private List<UserAddress> address;
}
// Address類(lèi)
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "user")
public class UserAddress {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String address;
@ManyToOne(cascade = CascadeType.ALL)
private User user;
}
// 性別枚舉類(lèi)
public enum SexEnum {
BOY,
GIRL
}
第二步:創(chuàng)建UserRepo ,我們繼承JpaSpecificationExecutor接口
public interface UserRepo extends JpaSpecificationExecutor<User> {
}
第三步:測(cè)試,構(gòu)造查詢(xún)條件
- name模糊查詢(xún)
- sex精準(zhǔn)查詢(xún)
- age范圍查詢(xún)
- address的in查詢(xún)
@Test
public void test02(){
User userQuery = User.builder()
.name("jack")
.email("123456@126.com")
.sex(SexEnum.BOY)
.age(20)
.address(Lists.newArrayList(UserAddress.builder().address("shanghai").build()))
.build();
List<User> userList = userRepo.findAll(new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicateList = new ArrayList<>();
// name模糊查詢(xún)
if(StringUtils.isNotBlank(userQuery.getName())) {
predicateList.add(cb.like(root.get("name"),userQuery.getName()));
}
// sex精準(zhǔn)查詢(xún)
if(userQuery.getSex()!=null) {
predicateList.add(cb.equal(root.get("sex"),userQuery.getSex()));
}
// age范圍查詢(xún)
if(userQuery.getAge()!=null){
predicateList.add(cb.greaterThanOrEqualTo(root.get("age"),userQuery.getAge()));
}
// 關(guān)聯(lián)查詢(xún)
if(!ObjectUtils.isEmpty(userQuery.getAddress())) {
predicateList.add(cb.in(root.join("address").get("address")).value(userQuery.getAddress().stream().map(a->a.getAddress()).collect(Collectors.toList())));
}
return query.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();
}
});
System.out.println(userList);
}
SQL執(zhí)行結(jié)果如下:
select user0_.id as id1_4_, user0_.age as age2_4_, user0_.create_time as create_t3_4_, user0_.email as email4_4_, user0_.name as name5_4_, user0_.sex as sex6_4_, user0_.update_time as update_t7_4_ from user user0_ inner join user_address address1_ on user0_.id=address1_.user_id where (user0_.name like ?) and user0_.sex=? and user0_.age>=20 and (address1_.address in (?))
2、JpaSpecificationExecutor語(yǔ)法詳解
先看源碼:
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(@Nullable Specification<T> spec);
List<T> findAll(@Nullable Specification<T> spec);
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
long count(@Nullable Specification<T> spec);
boolean exists(Specification<T> spec);
}
- findOne(@Nullable Specification spec):根據(jù)Specification 條件查詢(xún)單個(gè)對(duì)象
- findAll(@Nullable Specification spec):根據(jù)Specification 條件, 查詢(xún)List結(jié)果
- findAll(@Nullable Specification spec, Pageable pageable):根據(jù)Specification 條件, 分頁(yè)查詢(xún)
- findAll(@Nullable Specification spec, Sort sort):根據(jù)Specification 條件,帶排序的查詢(xún)結(jié)果
- count(@Nullable Specification spec): 根據(jù)Specification 條件,查詢(xún)數(shù)量
- exists(Specification spec):根據(jù)Specification 條件,查詢(xún)是否存在
2.1 Specification 接口

我們主要來(lái)看一下需要實(shí)現(xiàn)的方法:toPredicate(xx,xx,xx)
@Nullable Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
調(diào)試代碼

我們可以分別看到Root的實(shí)現(xiàn)類(lèi)是RootImpl,CriteriaQuery的實(shí)現(xiàn)類(lèi)是CriteriaQueryImpl,CriteriaBuilder的實(shí)現(xiàn)類(lèi)是CriteriaBuilderImpl。這三個(gè)實(shí)現(xiàn)類(lèi)都是由Hibernate實(shí)現(xiàn),也就是說(shuō)JpaSepcificationExecutor封裝了原本需要我們直接操作Hibernate中Criteria的API。
2.2 Root< User >root
解釋?zhuān)哼@個(gè)root就相當(dāng)于查詢(xún)和操作的實(shí)體對(duì)象的根,我們就可以通過(guò)Path get(xx)的方法,來(lái)獲取我們想要操作的字段。
<Y> Path<Y> get(String attributeName);
例如:獲取User實(shí)體類(lèi)中的name字段
predicateList.add(cb.like(root.get("name"),userQuery.getName()));
2.3 CriteriaQuery<?> query
這是一個(gè)Specific的頂層查詢(xún)對(duì)象,它包含著查詢(xún)的各個(gè)部分,比如select、from、where、group by 、Order by、distinct等。提供查詢(xún)Root的方法,我們來(lái)看一下源碼:

我們可以在上面的案例中看到query的用法:
return query.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();
我們可以再加一個(gè)groupBy的例子看看,如下所示:可以鏈?zhǔn)狡唇?/p>
return query.where(predicateList.toArray(new Predicate[predicateList.size()])).groupBy(root.get("age")).getRestriction();
執(zhí)行的SQL如下所示:

2.4 CriteriaBuilder cb
CriteriaBuilder是用來(lái)構(gòu)建CritiaQuery的構(gòu)建對(duì)象,其實(shí)就相當(dāng)于條件或者條件組合,并以Predicate的形式返回,基本提供了所有常用的方法。

通過(guò)源碼我們可以看到CriteriaBuilder 提供了and、any等用來(lái)查詢(xún)條件的組合;還提供了between、equal、exist等用來(lái)做查詢(xún)條件的查詢(xún)。
例如:equal
predicateList.add(cb.equal(root.get("sex"),userQuery.getSex()));
例如:like
predicateList.add(cb.like(root.get("name"),userQuery.getName()));
例如:greaterThanEqualTo
predicateList.add(cb.greaterThanOrEqualTo(root.get("age"),userQuery.getAge()));
解釋: 我們利用equal、like、greaterThanEqualTo 可以返回Predicate,而Predicate又可以組合起來(lái),就構(gòu)成了復(fù)雜的查詢(xún)條件,完全滿足日常開(kāi)發(fā)使用。
以上就是Spring Data JPA系列JpaSpecificationExecutor用法詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring Data JPA JpaSpecificationExecutor的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java常見(jiàn)延遲隊(duì)列的實(shí)現(xiàn)方案總結(jié)
Java延遲隊(duì)列(DelayQueue)是Java并發(fā)包中的一個(gè)類(lèi),它實(shí)現(xiàn)了BlockingQueue接口,且其中的元素必須實(shí)現(xiàn)Delayed接口,延遲隊(duì)列中的元素按照延遲時(shí)間的長(zhǎng)短進(jìn)行排序,本文給大家介紹了Java常見(jiàn)延遲隊(duì)列的實(shí)現(xiàn)方案總結(jié),需要的朋友可以參考下2024-03-03
SpringBoot實(shí)現(xiàn)簡(jiǎn)易支付寶網(wǎng)頁(yè)支付功能
小編最近實(shí)現(xiàn)一個(gè)功能基于springboot程序的支付寶支付demo,非常不錯(cuò)適合初學(xué)者入門(mén)學(xué)習(xí)使用,今天把SpringBoot實(shí)現(xiàn)簡(jiǎn)易支付寶網(wǎng)頁(yè)支付功能的示例代碼分享給大家,感興趣的朋友參考下吧2021-10-10
java金額數(shù)字轉(zhuǎn)中文工具類(lèi)詳解
這篇文章主要為大家詳細(xì)介紹了java金額數(shù)字轉(zhuǎn)中文工具類(lèi)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04
java實(shí)現(xiàn)的連接數(shù)據(jù)庫(kù)及模糊查詢(xún)功能示例
這篇文章主要介紹了java實(shí)現(xiàn)的連接數(shù)據(jù)庫(kù)及模糊查詢(xún)功能,結(jié)合實(shí)例形式分析了java基于jdbc連接數(shù)據(jù)庫(kù)及使用LIKE語(yǔ)句實(shí)現(xiàn)模糊查詢(xún)功能的相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
Java多線程異步調(diào)用性能調(diào)優(yōu)方法詳解
這篇文章主要為大家詳細(xì)介紹了Java多線程異步調(diào)用性能調(diào)優(yōu),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
Java計(jì)算數(shù)學(xué)表達(dá)式代碼詳解
這篇文章主要介紹了Java計(jì)算數(shù)學(xué)表達(dá)式代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以了解下。2017-12-12
Map映射LinkedHashSet與LinkedHashMap應(yīng)用解析
這篇文章主要為大家介紹了Map映射LinkedHashSet與LinkedHashMap的應(yīng)用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步2022-03-03

