文章目录
- 1. 使用继承的接口中的方法查询
- 2. 使用JPQL的方式查询
- 3. 使用SQL的方式查询
- 4. 方法命名规则查询
- 5. Specification动态查询
- 6. Spring Data JPA的多表查询
1. 使用继承的接口中的方法查询
在继承JpaRepository和JpaSpecificationExecutor接口后,我们就可以使用接口中定义的方法进行查询。继承JpaRepository后的方法列表:
继承JpaSpecificationExecutor的方法列表:
2. 使用JPQL的方式查询
使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询。@Query注解的使用非常简单,只需在方法上面标注该注解,同时提供一个JPQL查询语句即可
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
//使用jpql的方式查询
@Query(value="from Customer")
public List<Customer> findAllCustomer();
//使用jpql的方式查询,?1代表参数的占位符,其中 1对应方法中的参数索引
@Query(value="from Customer where custName = ?1")
public Customer findCustomer(String custName);
}
此外,也可以通过使用@Query来执行一个更新操作,为此,我们需要在使用@Query的同时,用@Modifying来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询。
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
@Query(value="update Customer set custName = ?1 where custId = ?2")
@Modifying
public void updateCustomer(String custName, Long custId);
}
3. 使用SQL的方式查询
Spring Data JPA同样也支持sql语句的查询,如下:
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
@Query(value="select * from cst_customer", nativeQuery=true)
public void findSql();
}
4. 方法命名规则查询
顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询
按照Spring Data JPA定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
//方法命名方式查询(根据客户名称查询客户)
public Customer findByCustName(String custName);
}
具体的关键字,使用方法和生产成SQL如下表所示:
5. Specification动态查询
有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。
JpaSpecificationExecutor中定义的方法:
public interface JpaSpecificationExecutor<T> {
//根据条件查询一个对象
T findOne(Specification<T> spec);
//根据条件查询集合
List<T> findAll(Specification<T> spec);
//根据条件分页查询
Page<T> findAll(Specification<T> spec, Pageable pageable);
//排序查询查询
List<T> findAll(Specification<T> spec, Sort sort);
//统计查询
long count(Specification<T> spec);
}
对于JpaSpecificationExecutor,这个接口基本是围绕着Specification接口来定义的。我们可以简单的理解为,Specification构造的就是查询条件。Specification接口中只定义了如下一个方法:
/**
* root:Root接口,代表查询的根对象,可以通过 root获取实体中的属性
* query:代表一个顶层查询对象,用来自定义查询(很少使用)
* cb:用来构建查询,此对象里有很多条件方法
**/
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
使用案例:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpecificationTest {
@Autowired
private CustomerDao customerDao;
@Test
public void testSpecifications() {
//使用匿名内部类的方式,创建一个 Specification的实现类,并实现 toPredicate方法
Specification <Customer> spec = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate p1 = cb.like(root.get("custName").as(String.class), "张%");
Predicate p2 = cb.equal(root.get("custIndustry").as(String.class), "IT");
//cb.and(以与的形式拼接多个查询条件),cb.or(以或的形式拼接多个查询条件)
Predicate and = cb.and(p1, p2);
return and;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
@Test
public void testSort() {
//构造查询条件
Specification<Customer> spec = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("custName").as(String.class), "张%");
}
};
//构造排序参数
Sort sort = new Sort(Sort.Direction.DESC, "custId");
List<Customer> list = customerDao.findAll(spec, sort);
for (Customer customer : list) {
System.out.println(customer);
}
}
@Test
public void testPage() {
//构造查询条件
Specification<Customer> spec = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("custName").as(String.class), "张%");
}
};
//构造分页参数
Pageable pageable = new PageRequest(0, 5);
Page<Customer> page = customerDao.findAll(spec, pageable);
System.out.println(page.getContent()); //得到数据集合列表
System.out.println(page.getTotalElements()); //得到总条数
System.out.println(page.getTotalPages()); //得到总页数
}
}
CriteriaBuilder中方法对应关系如下所示:
6. Spring Data JPA的多表查询
- 对象导航查询
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个客户,可以调用Customer类中的getLinkMans()方法来获取该客户的所有联系人。对象导航查询的使用要求是:两个对象之间必须存在关联关系。
@Test
public void testFind() {
Customer customer = customerDao.findOne(1l);
Set<LinkMan> linkMans = customer.getLinkMans(); //对象导航查询
for(LinkMan linkMan : linkMans) {
System.out.println(linkMan);
}
}
- 使用Specification查询
@Test
public void testFind() {
Specification<LinkMan> spec = new Specification<LinkMan>() {
public Predicate toPredicate(Root<LinkMan> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//Join代表链接查询,通过 root对象获取
//创建的过程中,第一个参数为关联对象的属性名称,
//第二个参数为连接查询的方式(JoinType.LEFT,JoinType.INNER,JoinType.RIGHT)
Join<LinkMan, Customer> join = root.join("customer", JoinType.INNER);
return cb.like(join.get("custName").as(String.class), "张%");
}
};
List<LinkMan> list = linkManDao.findAll(spec);
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
}