本章介绍一下Spring Data Jpa高级查询,上一章讲的JPQL,JPQL使用起来非常方便,但是如果SQL有一个词不小心写错了,只有在程序运行时才能发现错误在哪,这是一个弊端,如果想要在编译期间发现错误该怎么做呢,答案是使用Spring Data Jpa高级查询。
@PersistenceContext
private EntityManager entityManager;
首先注入entityManager
CriteriaBuilder cb = entityManager.getCriteriaBuilder (); // criteriaQuery工厂
CriteriaQuery cq = cb.createQuery(); //查询语句构造器
Root 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 users = query.getResultList();
这就是一个简单的Criteria查询的例子了,下面说一下怎么使用动态参数,在上方参数20的地方改成:
CriteriaBuilder cb = entityManager.getCriteriaBuilder (); // criteriaQuery工厂
CriteriaQuery cq = cb.createQuery(); //查询语句构造器
Root root = cq.from(User.class); //获取查询根对象
cq.select(root); // select u from User u
Predicate pre = cb.greaterThan(root.get("age").as(Integer.class), cb.parameter(Integer.class, "age")); // 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);
query.setparameter("age", 20);//这里可以插入动态参数
List users = query.getResultList();
只查询部分字段:
把cq.select(root)改成cq.select(root.get(“字段名”))即可;
有多个字段就 cq.multiselect(root.get("age"), root.get("name").......)即可;
此时,结果集映射有两种方法
①List
②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));
public interface UserRepository extends JpaRepository , JapSpecificationExecutor{
}
repository继承了JapSpecificationExecutor之后,在UserServiceImpl中调用userRepository :
public List getUsers(){
return userRepository.findAll(new Specification(){
@Override
public Predicate toPredicate(Root, CriteriaQuery> cq, CriteriaBuilder cb){
List preList = new ArrayList();
// 跟上面Criteria的条件构造是一样的
// ..........
// ..........
// 条件构造完毕,都在 preList 里面
return cq.where(preList.toArray(new Predicate[preList.size()])).getRestriction();
}
}) ;
}
三、@Query和@NamedQuery查询
这个注解允许我们在接口的方法处使用自定义的查询语句(JPQL或者SQL),
public interface UserRepository extends JpaRepository , JapSpecificationExecutor{
@Query(value="select u from User u where name like ?1") // 这里可以使用位置参数
public List findUserByName(String name);
// @Query(value="select u from User u where name like :name") 这里也可以使用命名参数
// public List 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 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 {}
这就是spring data jpa的高级查询基本用法,其实用法还有很多,详细的可以看看API,很多方法这都没有介绍,只介绍了最基础的用法,供大家入门用。