本章介紹一下Spring Data Jpa高級查詢,上一章講的JPQL,JPQL使用起來非常方便,但是如果SQL有一個詞不小心寫錯了,只有在程序運行時才能發現錯誤在哪,這是一個弊端,如果想要在編譯器發現錯誤該怎麼做呢,答案是使用Spring Data Jpa高級查詢。
一、Criteria查詢
@PersistenceContext
private EntityManager entityManager;
首先注入entityManager
CriteriaBuilder cb = entityManager.getCriteriaBuilder (); // criteriaQuery工廠
CriteriaQuery cq = cb.createQuery(); //查詢語句構造器
Root<User> root = cq.from(User.class); //獲取查詢根對象
cq.select(root); // select u from User u
Predicate pre = cb.greaterThan(root.get("age").as(Integer.class), 20); // age大於20
cq.where(pre); // select u from User u where u.age > 20
// 上面這一串的目的就是爲了構造出 select u from User u where u.age > 20 的JPQL語句
Query query = em.createQuery(cq);
List<User> users = query.getResultList();
這就是一個簡單的Criteria查詢的例子了,下面說一下怎麼使用動態參數,在上方參數20的地方改成:
Predicate pre = cb.greaterThan(root.get("age").as(Integer.class), cb.parameter(Integer.class, "age"));
//然後在後面:
query.setparameter("age", 20);
只查詢部分字段:
把cq.select(root)改成cq.select(root.get("age"))即可;
有多個字段就 cq.multiselect(root.get("age"), root.get("name").......)即可;
此時,結果集映射有兩種方法
①List<User> 改成List<Object[]>,手動設置值到實體屬性的映射;
②cq.select(cb.construct(User.class, root.get("age"),.......其他字段....)); 使用構造方法自動轉換成實體
Fetch查詢:
在cq.select 前加上:
Fetch rootFetch = root.fetch("interests"); // 關聯查詢出用戶的所有性趣
想要在程序中手動控制fetch,需要先再@ManyToMany等其他註解中將fetch設置成懶加載,然後在程序中控制。
設置JOIN:
在cq.select前加:
root.join("interests", JoinType.LEFT); // select u from User u left join u.interests where u.age > 20
結果集排序:
在cq.orderBy後面:
cq.orderBy(cb.desc(root.get("age")), cb.asc(root.get("name")));
多個查詢條件:
Predicate pre = cb.greaterThan(root.get("age").as(Integer.class), 20); // age大於20
Predicate pre2 = cb.lessThan(root.get("age").as(Integer.class), 40); // age小於20
cq.where(pre)改成cq.where(pre,pre2);
也可以使用cb來設置and,or的關係,如;
cq.where(cb.and(pre, pre2));
二、使用JpaSpecificationExcutor查詢
public interface UserRepository extends JpaRepository<User, Integer> , JapSpecificationExecutor<User>{
}
repository繼承了JapSpecificationExecutor之後,在UserServiceImpl中調用userRepository :
public List<User> getUsers(){
return userRepository.findAll(new Specification<User>(){
@Override
public Predicate toPredicate(Root<User>, CriteriaQuery<?> cq, CriteriaBuilder cb){
List<Predicate> preList = new ArrayList();
// 跟上面Criteria的條件構造是一樣的
// ..........
// ..........
// 條件構造完畢,都在 preList 裏面
return cq.where(preList.toArray(new Predicate[preList.size()])).getRestriction();
}
}) ;
}
三、@Query和@NamedQuery查詢
這個註解允許我們在藉口的方法處使用自定義的查詢語句(JPQL或者SQL),
public interface UserRepository extends JpaRepository<User, Integer> , JapSpecificationExecutor<User>{
@Query(value="select u from User u where name like ?1") // 這裏可以使用位置參數
public List<User> findUserByName(String name);
// @Query(value="select u from User u where name like :name") 這裏也可以使用命名參數
// public List<User> findUserByName(@Param("name") String name);
}
如果想使用原生sql的話,@Query註解裏有一個屬性可以配置:
@Query(value="select u from user u where name like ?1", nativeQuery = true) // 設置爲true就表示使用原生sql查詢
@NamedQuery:命名查詢,是調用實體管理器來執行的命名查詢,有一些經常用到的查詢,我們把它先寫好,之後根據名稱直接調用即可。
@NamedQuery的自定義查詢寫到實體上,
@NamedQuery(name = "findUserByName", query="select u from User s where u.name like ?1")
@Entity
@Table("user")
public class User {}
使用實體管理器調用:
// 使用命名查詢
entityManager.createNamedQuery("findUserByName");
query.setParameter(1, "%王%");
List<User> users = query.getResultList();
當有多個命名查詢時,可用@NamedQueries包裹起來
@NamedQueries({
@NamedQuery(name = "findUserByName", query="select u from User s where u.name like ?1"),
@NamedQuery(name = "findUserByName2", query="select u from User s where u.name like ?1"),
@NamedQuery(name = "findUserByName2", query="select u from User s where u.name like ?1")
})
@Entity
@Table("user")
public class User {}
好,本節課程就到這裏,下課~~~~~~~~~~!!!!!!!!!!!!!!!!!!!!