Spring Data JPA雖然大大的簡(jiǎn)化了持久層的開發(fā),但是在實(shí)際開發(fā)中,很多地方都需要高級(jí)動(dòng)態(tài)查詢
Criteria API
Criteria 查詢是以元模型的概念為基礎(chǔ)的,元模型是為具體持久化單元的受管實(shí)體定義的屡限,這些實(shí)體可以是實(shí)體類,嵌入類或者映射的父類磁浇。
CriteriaQuery接口:代表一個(gè)specific的頂層查詢對(duì)象,它包含著查詢的各個(gè)部分朽褪,比如:select 置吓、from、where鞍匾、group by交洗、order by等注意:CriteriaQuery對(duì)象只對(duì)實(shí)體類型或嵌入式類型的Criteria查詢起作用
Root接口:代表Criteria查詢的根對(duì)象,Criteria查詢的查詢根定義了實(shí)體類型橡淑,能為將來導(dǎo)航獲得想要的結(jié)果,它與SQL查詢中的FROM子句類似
? 1:Root實(shí)例是類型化的咆爽,且定義了查詢的FROM子句中能夠出現(xiàn)的類型梁棠。
? 2:查詢根實(shí)例能通過傳入一個(gè)實(shí)體類型給 AbstractQuery.from方法獲得。
? 3:Criteria查詢斗埂,可以有多個(gè)查詢根符糊。
? 4:AbstractQuery是CriteriaQuery 接口的父類,它提供得到查詢根的方法呛凶。CriteriaBuilder接口:用來構(gòu)建CritiaQuery的構(gòu)建器對(duì)象Predicate:一個(gè)簡(jiǎn)單或復(fù)雜的謂詞類型男娄,其實(shí)就相當(dāng)于條件或者是條件組合
如果編譯器能夠?qū)Σ樵儓?zhí)行語(yǔ)法正確性檢查,那么對(duì)于 Java 對(duì)象而言該查詢就是類型安全的。Java?Persistence API (JPA) 的 2.0 版本引入了 Criteria API模闲,這個(gè) API 首次將類型安全查詢引入到 Java 應(yīng)用程序中建瘫,并為在運(yùn)行時(shí)動(dòng)態(tài)地構(gòu)造查詢提供一種機(jī)制。
JPA元模型
在JPA中,標(biāo)準(zhǔn)查詢是以元模型的概念為基礎(chǔ)的.元模型是為具體持久化單元的受管實(shí)體定義的.這些實(shí)體可以是實(shí)體類,嵌入類或者映射的父類.提供受管實(shí)體元信息的類就是元模型類.
使用元模型類最大的優(yōu)勢(shì)是憑借其實(shí)例化可以在編譯時(shí)訪問實(shí)體的持久屬性.該特性使得criteria 查詢更加類型安全.
如下,Item
實(shí)體類對(duì)應(yīng)的元模型Item_
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Item.class)
public abstract class Item_ {
public static volatile SingularAttribute<Item, Integer> itemId;
public static volatile SingularAttribute<Item, String> itemName;
public static volatile SingularAttribute<Item, Integer> itemStock;
public static volatile SingularAttribute<Item, Integer> itemPrice;
}
這樣的元模型不用手動(dòng)創(chuàng)建,在Maven中添加插件,編譯之后@Entity注解的類就會(huì)自動(dòng)生成對(duì)應(yīng)的元模型
<!--hibernate JPA 自動(dòng)生成元模型-->
<!-- 相關(guān)依賴 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.2.10.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
</plugin>
方法不止一種,具體見:Chapter 2. Usage
使用criteria 查詢簡(jiǎn)單Demo
@Service
public class ItemServiceImpl implements ItemService {
@Resource
private EntityManager entityManager;
@Override
public List<Item> findByConditions(String name, Integer price, Integer stock) {
//創(chuàng)建CriteriaBuilder安全查詢工廠
//CriteriaBuilder是一個(gè)工廠對(duì)象,安全查詢的開始.用于構(gòu)建JPA安全查詢.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
//創(chuàng)建CriteriaQuery安全查詢主語(yǔ)句
//CriteriaQuery對(duì)象必須在實(shí)體類型或嵌入式類型上的Criteria 查詢上起作用尸折。
CriteriaQuery<Item> query = criteriaBuilder.createQuery(Item.class);
//Root 定義查詢的From子句中能出現(xiàn)的類型
Root<Item> itemRoot = query.from(Item.class);
//Predicate 過濾條件 構(gòu)建where字句可能的各種條件
//這里用List存放多種查詢條件,實(shí)現(xiàn)動(dòng)態(tài)查詢
List<Predicate> predicatesList = new ArrayList<>();
//name模糊查詢 ,like語(yǔ)句
if (name != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
itemRoot.get(Item_.itemName), "%" + name + "%")));
}
// itemPrice 小于等于 <= 語(yǔ)句
if (price != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
itemRoot.get(Item_.itemPrice), price)));
}
//itemStock 大于等于 >= 語(yǔ)句
if (stock != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.ge(
itemRoot.get(Item_.itemStock), stock)));
}
//where()拼接查詢條件
query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
TypedQuery<Item> typedQuery = entityManager.createQuery(query);
List<Item> resultList = typedQuery.getResultList();
return resultList;
}
}
criteriaBuilder中各方法對(duì)應(yīng)的語(yǔ)句
equle : filed = value
gt / greaterThan : filed > value
lt / lessThan : filed < value
ge / greaterThanOrEqualTo : filed >= value
le / lessThanOrEqualTo: filed <= value
notEqule : filed != value
like : filed like value
notLike : filed not like value
如果每個(gè)動(dòng)態(tài)查詢的地方都這么寫,那就感覺太麻煩了.
那實(shí)際上,在使用Spring Data JPA的時(shí)候啰脚,只要我們的Repo層接口繼承JpaSpecificationExecutor接口就可以使用Specification進(jìn)行動(dòng)態(tài)查詢了,我們先看下JpaSpecificationExecutor接口:
public interface JpaSpecificationExecutor<T> {
T findOne(Specification<T> var1);
List<T> findAll(Specification<T> var1);
Page<T> findAll(Specification<T> var1, Pageable var2);
List<T> findAll(Specification<T> var1, Sort var2);
long count(Specification<T> var1);
}
在這里有個(gè)很重要的接口Specification
public interface Specification<T> {
Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}
這個(gè)接口只有一個(gè)方法,返回動(dòng)態(tài)查詢的數(shù)據(jù)結(jié)構(gòu),用于構(gòu)造各種動(dòng)態(tài)查詢的SQL
Specification接口示例
public Page<Item> findByConditions(String name, Integer price, Integer stock, Pageable page) {
Page<Item> page = itemRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicatesList = new ArrayList<>();
//name模糊查詢 ,like語(yǔ)句
if (name != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
root.get(Item_.itemName), "%" + name + "%")));
}
// itemPrice 小于等于 <= 語(yǔ)句
if (price != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
root.get(Item_.itemPrice), price)));
}
//itemStock 大于等于 >= 語(yǔ)句
if (stock != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.ge(
root.get(Item_.itemStock), stock)));
}
return criteriaBuilder.and(
predicatesList.toArray(new Predicate[predicatesList.size()]));
}, page);
return page;
}
在這里因?yàn)?code>findAll(Specification<T> var1, Pageable var2)方法中參數(shù)
Specification<T>
是一個(gè)匿名內(nèi)部類那這里就可以直接用lambda表達(dá)式直接簡(jiǎn)化代碼.
這樣寫,就比用CriteriaBuilder安全查詢工廠簡(jiǎn)單多了.
調(diào)用:
Page<Item> itemPageList = findByConditions("車", 300, null, new PageRequest(1, 10));
利用JPA的Specification<T>
接口和元模型就實(shí)現(xiàn)動(dòng)態(tài)查詢了.
那其實(shí)這樣每一個(gè)需要?jiǎng)討B(tài)查詢的地方都需要寫一個(gè)這樣類似的findByConditions
方法,感覺也很麻煩了.當(dāng)然是越簡(jiǎn)化越好.
下一篇將會(huì)講一個(gè)JPASpecification
更方便的使用.
原文鏈接:Spring-Data-JPA criteria 查詢 | 火堯