背景:
假设我们有一个数据表叫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 |
|---|---|---|
| And | findByLastnameAndFirstname | where x.lastname=?1 and x.firstname=?2 |
| Or | findByLastnameOrFirstname | where x.lastname=?1 or x.firstname=?2 |
| Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | where x.firstname=?1 |
| Between | findByStartDateBetween | where x.startDate between ?1 and ?2 |
| LessThan | findByAgeLessThan | where x.age<?1 |
| LessThanEqual | findByAgeLessThanEqual | where x.age <=?1 |
| GreaterThan | findByAgeGreaterThan | where x.age > ?1 |
| GreaterThanEqual | findByAgeGreaterEqual | where x.age >=?1 |
| After | findByStartDateAfter | where x.startDate < ?1 |
| Before | findByStartDateBefore | where x.startDate <?1 |
| IsNull | findByAgeIsNull | where x.age is null |
| IsNotNull,NotNull | findByAges(Is)NotNull | where x.age not null |
| Like | findByFirstnameLike | where x.firstname like ?! |
| NotLike | findByFirstnameNotLike | where x.firstname not like ?1 |
| StartingWith | findByFirstnameEndingWith | where x.firstname like ?1(参数前面加%) |
| EndingWith | findByFirstnameEndingWith | where x.firstname like ?1(参数的后面加%) |
| Containing | findByFirstnameContaining | where x.firstname like ?1(参数的前后加%) |
| OrderBy | findByAgeOrderByLastnameDesc | where x.age=?1 order by x.lastname desc |
| Not | findByLastnameNot | where x.lastname <>?1 |
| In | findByAgeNotIn(Collection<Age> age) | where x.age in ?1 |
| NotIn | findByAgeNotIn(Collection<Age> age) | where x.age not in ?1 |
| True | findByActiveTrue | where x.active=true |
| False | findByActiveFalse() | where x.active=false |
| IgnoreCase | findByFirstnameIgnoreCase | where 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实战》
本文介绍了Spring Data JPA的查询方式,包括基于属性名的查询、使用NamedQuery、@Query注解进行复杂查询,以及Specification接口进行准则查询。同时,讲解了如何实现排序和分页操作。

被折叠的 条评论
为什么被折叠?



