全面解析JPA 倉庫repository中的findAll()方法

解析JPA倉庫repository的findAll()方法

源碼

Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);

(1) Specification spec 對象

(2) Pageable pageable 對象

下面是findAll()實現類

public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
		//參數spec隻是一個實例,沒有查詢條件
		TypedQuery<T> query = getQuery(spec, pageable);
		return isUnpaged(pageable) ? new PageImpl<T>(query.getResultList())
				: readPage(query, getDomainClass(), pageable, spec);
	}

getQuery(spec,pageable)方法作用

返回一個指定操作表,指定返回項,指定排序方式,指定查詢條件的query對象

1.其中getDomainClass()作用

returns the actual domain class type. 也就是數據表對應的實體類

protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {
		Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
		return getQuery(spec, getDomainClass(), sort);
	}

2.執行getQuery方法

protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<S> query = builder.createQuery(domainClass);
		Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
		query.select(root);
		if (sort.isSorted()) {
			query.orderBy(toOrders(sort, root, builder));
		}
		return applyRepositoryMethodMetadata(em.createQuery(query));
	}

其中em是EntityManager對象,用來獲取CriteriaBuilder 實例(參考鏈接CriteriaBuilder動態構造查詢)

  • CriteriaBuilder :可以用於創建CriteriaQuery、CriteriaUpdate和CriteriaDelete等
  • createQuery:hibernate的SQL操作方法,用來生成一個基於 HQL 查詢字符串的 Query 對象,domainClass指的是表對應的實體類

2.1 applySpecificationToCriteria(…)方法:

將Specification中生成的Predicate應用於Criteria

private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,CriteriaQuery<S> query) {
		Assert.notNull(domainClass, "Domain class must not be null!");
		Assert.notNull(query, "CriteriaQuery must not be null!");
		Root<U> root = query.from(domainClass);
		if (spec == null) {
			return root;
		}
		CriteriaBuilder builder = em.getCriteriaBuilder();
		Predicate predicate = spec.toPredicate(root, query, builder);
		if (predicate != null) {
			query.where(predicate);
		}
		return root;
	}

spec.toPredicate(…)方法,是spec實例調用Spec類中的toPredicate(),獲取查詢條件。

where()源碼翻譯:

query.where(predicate)作用,根據predicate(查詢條件的集合)修改query限制查詢結果(如果之前有條件限制,會自動替換),如果此次沒有添加任何限制,之前的條件限制會被移除(也就是說,條件限制會覆蓋),這裡的where()重寫瞭AbstractQuery接口中where(),predicate條件可以為空也可以是多個,返回結果是the modified query

2.2 回到getQuery方法中

query.select(root);
		if (sort.isSorted()) {
			query.orderBy(toOrders(sort, root, builder));
		}
  • query.select():指定要在查詢結果中返回的項(覆蓋,若之前有所指定,則覆蓋),這裡指定返回項是表對應的實體類,返回結果是the modified query
  • query.orderBy():修改排序規則,返回結果也是the modified query,這裡不對 toOrders過多的即使
return applyRepositoryMethodMetadata(em.createQuery(query));
  • em.createQuery(query):創建TypedQuery 實例,用來執行executing a criteria query

執行查詢語句,返回結果集(不做詳細分析)

return isUnpaged(pageable) ? new PageImpl<T>(query.getResultList())
				: readPage(query, getDomainClass(), pageable, spec);
  • query.getResultList():返回查詢結果(相當於hibernate中list()方法執行hql,返回結果)
  • getResultList():方法會調用doList()方法

這個方法中會生成SQL語句expandeQuery:

select generatedAlias0 from Students as generatedAlias0 where 1=1 order by generatedAlias0.studentAge desc

jpa Repository的findOne正確寫法和findAll

@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Integer id) {
    User user = new User();
    user.setId(id);
    Example<User> example = Example.of(user);
    Optional<User> one = userRepository.findOne(example);
    return one.get();
}
@GetMapping("/user/all")
public List<User> getAll() {
    List<User> all = userRepository.findAll();
    System.out.println(all);
    return  all;
}

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: