文章目录

  • 1. 使用继承的接口中的方法查询
  • 2. 使用JPQL的方式查询
  • 3. 使用SQL的方式查询
  • 4. 方法命名规则查询
  • 5. Specification动态查询
  • 6. Spring Data JPA的多表查询


1. 使用继承的接口中的方法查询

在继承JpaRepository和JpaSpecificationExecutor接口后,我们就可以使用接口中定义的方法进行查询。继承JpaRepository后的方法列表:

Java JPA 查询SUM jpa查询数据_Java JPA 查询SUM


继承JpaSpecificationExecutor的方法列表:

Java JPA 查询SUM jpa查询数据_Data_02

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如下表所示:

Java JPA 查询SUM jpa查询数据_JPA_03

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中方法对应关系如下所示:

Java JPA 查询SUM jpa查询数据_Customer_04

6. Spring Data JPA的多表查询

  1. 对象导航查询
    对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过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);
	}
}
  1. 使用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);
	}
}