[spring-jpa]定义查询方法

本文介绍了Spring Data JPA的查询方式,包括基于属性名的查询、使用NamedQuery、@Query注解进行复杂查询,以及Specification接口进行准则查询。同时,讲解了如何实现排序和分页操作。

背景:

假设我们有一个数据表叫Person,有ID(Number)、NAME(Varchar2)、AGE(Number)、ADDRESS(Varchar2)几个字段;对应的实体类叫Person,分别有id(long),name(String),age(Integer),address(String)。

1. 根据属性名查询

Spring Data jpa 支持通过定义在Repository接口中的方法名来定义查询,而方法名时根据实体类的属性名来确定的。

  • 常规查询。根据属性名来定义查询的方法,示例如下:
	public interface PersonRepository extends JpaRepository<Person,Long> {
		/**
		* 通过名字相等查询,参数为name
		* 相当于JPQL:select p from Person p where p.name = ?1	
		*/
		List<Person> findByName(String name);

		/**
		*
		* 通过名字like查询,参数为name
		* 相当于JPQL:select p from Person p where p.name like ?1
		*/
		List<Person> findByNameLike(String name);

		/**
		*
		* 通过名字和地址查询,参数为name 和 address
		* 相当于JPQL:select p from Person p where p.name=?1 and p.address=?2
		*
		*/
		List<Person> findByNameAndAddress(String name,String address);
	}

从代码中看出,这里使用了findBy、Like、And这样的关键字。其中findBy可以用find、read、readBy、query、queryBy、get、getBy来代替。

而Like和and这类查询关键字,说明如下表:

关键字示例同功能JPQL
AndfindByLastnameAndFirstnamewhere x.lastname=?1 and x.firstname=?2
OrfindByLastnameOrFirstnamewhere x.lastname=?1 or x.firstname=?2
Is,EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEqualswhere x.firstname=?1
BetweenfindByStartDateBetweenwhere x.startDate between ?1 and ?2
LessThanfindByAgeLessThanwhere x.age<?1
LessThanEqualfindByAgeLessThanEqualwhere x.age <=?1
GreaterThanfindByAgeGreaterThanwhere x.age > ?1
GreaterThanEqualfindByAgeGreaterEqualwhere x.age >=?1
AfterfindByStartDateAfterwhere x.startDate < ?1
BeforefindByStartDateBeforewhere x.startDate <?1
IsNullfindByAgeIsNullwhere x.age is null
IsNotNull,NotNullfindByAges(Is)NotNullwhere x.age not null
LikefindByFirstnameLikewhere x.firstname like ?!
NotLikefindByFirstnameNotLikewhere x.firstname not like ?1
StartingWithfindByFirstnameEndingWithwhere x.firstname like ?1(参数前面加%)
EndingWithfindByFirstnameEndingWithwhere x.firstname like ?1(参数的后面加%)
ContainingfindByFirstnameContainingwhere x.firstname like ?1(参数的前后加%)
OrderByfindByAgeOrderByLastnameDescwhere x.age=?1 order by x.lastname desc
NotfindByLastnameNotwhere x.lastname <>?1
InfindByAgeNotIn(Collection<Age> age)where x.age in ?1
NotInfindByAgeNotIn(Collection<Age> age)where x.age not in ?1
TruefindByActiveTruewhere x.active=true
FalsefindByActiveFalse()where x.active=false
IgnoreCasefindByFirstnameIgnoreCasewhere UPPER(x.firstname) ==UPPER(?1)

  • 限制结果数量。结果数量是用top和first关键字来实现的:
public interface PersonRepository extends JpaRepository<Person,Long>{
	/**
	* 获得符合查询条件的前10条数据
	*
	**/
	List<Person> findFirst10ByName(String name);	
	
	/**
	* 获得符合条件的前30条数据
	*
	**/
	List<Person> findTop30ByName(String name);
}

2. 使用JPA的NamedQuery查询

Spring Data JPA支持用JPA的NameQuery来定义查询方法,即一个名称映射一个查询语句,定义如下:

@Entity
@NamedQuery(name="Person.findByName",query="select p from Person p where p.name=?1")
public class Person{
}

使用如下语句:

public interface PersonRepository extends JpaRepository<Person,Long>{
	/**
	* 这时我们使用的是NameQuery里定义的查询语句,而不是根据方法名称查询
	*/
	List<Person> findByName(String name);
	
}

3.使用@Query查询

  • 使用参数索引。Spring Data JPA 还支持用@Query注解在接口的方法上实现查询,例如:
 public interface PersonRepository extends JpaRepository<Person,Long>{
	@Query("select p from person p where p.address=?1")
	List<Person> findByAddress(String address);
	}
  • 使用命名参数。上面的例子是使用参数的索引号来查询的,在Spring Data JPA里还支持在语句里用名称来匹配查询参数,例如:
 public interface PersonRespository extends JpaRepository<Person,Long>{
	@Query("select p from Person p where p.address= :address")
	List<Person> findByAddress(@Param("address") String address);
	}
  • 更新查询。Spring Data JPA支持 @Modifying 和 @Query 注解组合来实现更新查询,如:
 @Modifying
 @Transactional
 @Query("update Person p set p.name = ?1")
 int setName(String name);

其中返回值int表示更新语句影响的行数。

4. Specification

JPA提供了基于准则查询的方式,即Criteria查询。而Spring Data JPA 提供了一个Specification(规范)接口让我们可以更方便的构造准则查询,Specification接口定义了一个toPredicate方法用来构造查询条件。

4.1 定义

我们的接口类必须实现JpaSpecificationExecutor接口,代码如下:

public interface PersonRepository extends JpaRepository<Person,Long>,JpaSpecificationExecutor<Person>{

}

然后定义Criteria查询,代码如下:


public class CustomerSpecs{
	public static Specification<Person> personFromChina(){
		return new Specification<Person>(){
				@Override
				public Predicate toPredicate(Root<Person> root,CriteriaQuery<?> query,CriteriaBuilder cb){
					return cb.equal(root.get("address"),"china");
			}
		};
	}
}

我们使用Root来获得需要查询的属性,通过CriteriaBuilder构造查询条件,本例的含义是查出所有来自中国的人。

注意:CriteriaBuilder、CriteriaQuery、Predicate、Root都是来自JPA的接口

CriteriaBuilder的条件构造请查看其Api获取详细信息。

4.2 使用-静态导入

import static com.test.specs.CustomerSpecs.*;

注入personRepository的Bean之后:

List<Person> people = personRepository.findAll(personFromChina());

5. 排序与分页

5.1 定义

public interface PersonRepository extends JpaRepository<Person,Long>{
	List<Person> findByName(String name,Sort sort);
	Page<Person> findByName(String name,Pageable pageable);
}

5.2 使用排序

List<Person> people = personRepository.findByName("xx",new Sort(Direction.ASC,"age"));

5.3 使用分页

Page<Person> people2 = personRepository.findByName("xx",new PageRequest(0.10));

其中,Page接口可以获得当前页面的记录,总页数,总记录数,是否有上一页或下一页等。


参考《Java EE开发的颠覆者:Spring Boot实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值