查询、分页、排序

查询、分页、排序

查询

查询有

  • 方法名字方式查询

  • @Query注解方式查询

  • 动态SQL方式查询

  • Example方式查询

JpaJpaRepository提供了如下表所述的内置查询。

  • List<T> findAll(); - 返回所有实体

  • List<T> findAllById(Iterable<ID> var1); - 返回指定id的所有实体

  • T getOne(ID var1); - 根据id返回对应的实体,如果未找到,则返回空。

  • List<T> findAll(Sort var1); - 返回所有实体,按照指定顺序返回。

  • Page<T> findAll(Pageable var1); - 返回实体列表,实体的offset 和limit通过pageable来指定

方法名字方式查询方式

Spring Data 通过查询的方法名和参数名来自动构造一个JPA QQL查询

比如

public interface UserRepository extends JpaRepository<User, Integer> {
    public User findByName(String name);
}

方法名和参数名要遵守一定的规则, Spring Data JPA 才能自动转换为JPQL:

  • 方法名通常包含多个实体属性用于查询,属性之间可以使用AND和OR连接,也支持Between、LessThan、GreaterThan、Like;

  • 方法名可以以findBy、getBy、queryBy 开头;

  • 查询结果可以排序,方法名包含OrderBy+属性+ASC(DESC);

  • 可以通过Top、First来限定查询的结果集;

  • 一些特殊的参数可以出现在参数列表里,比如Pageeable、Sort

例子:

// 根据名字查询,且按照名字升序
List<Person> findByLastnameOrderByFirstnameAsc(String name);

// 根据名字查询,且使用翻页查询
Page<User> findByLastname(String lastname, Pageable pageable);

// 查询满足条件的前10个用户
List<User> findFirst10ByLastname(String lastname, Sort sort);

// 使用And联合查询
List<Person> findByFirstnameAndLastname(String firstname, String lastname);

// 使用Or查询
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);

// 使用like查询,name 必须包含like中的%或者?
public User findByNameLike(String name);

Keyword

Sample

JPQL snippet

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

findByAgeGreaterThanEqual

… 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

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… 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.firstame) = UPPER(?1)

注意:Spring Data的Query 适用于关系数据库操作,也适合NOSQL。大部分Spring Boot应用中,Query构造只能创建一些简单的查询。但对于NOSQL来说已经足够了,不需要自己再构造NOSQL查询

@Query注解方式查询

注解Query允许在方法上使用JPQL

其中操作针对的是对象名和对象属性名,而非数据库中的表名和字段名

@Query("select u form User u where u.name=?1 and u.depantment.id=?2");
public User findUser(String name, Integer departmentId);
@Query("form User u where u.name=?1 and u.depantment.id=?2");
public User findUser(String name, Integer departmentId);

如果使用SQL而不是JPSQL,可以使用nativeQuery属性,设置为true

@Query(value="select * from user where name=?1 and department_id=?2", nativeQuery=true)
public User nativeQuery(String name, Integer departmentId);

无论JPQL,还是SQL,都支持"命名参数":

@Query(value="select * from user where name=:name and department_id=:departmentId", nativeQuery=true)
public User nativeQuery2(String name, Integer departmentId);

如果SQL活着JPQL查询结果集并非Entity,可以用Object[]数组代替,比如分组统计每个部分的用户数:

@Query(value="select department_id,count(*) from user group by department_id", nativeQuery=true)
public List<Object[]> queryUserCount()

这条查询将返回数组,对象类型依赖于查询结果,被示例中,返回的是String和BigInteger类型

查询时可以使用Pageable和Sort来完成翻页和排序。

@Query("select u from User u where department.id=?1")
public Page<User> QueryUsers(Integer departmentId, Pageable page);

@Query 还允许SQL更新、删除语句,此时必须搭配@Modifying使用,比如:

@Modifying
@Query("update User u set u.name= ?1 where u.id= ?2")
int updateName(String name, Integer id);

动态SQL方式查询

spring data jpa 利用JpaSpecificationExecutor做复杂查询

Spring data JPA中使用Specifications动态构建查询

Example方式查询

允许根据实体创建一个Example对象,Spring Data通过Example对象来构造JPQL。但是使用不灵活条件是AND,不能使用or,时间的大于小于,between等。

继承JpaRepository

<S extends T> List<S> findAll(Example<S> var1);

<S extends T> List<S> findAll(Example<S> var1, Sort var2);
public List<User> getByExample(String name) {
    Department dept = new Department();
    dept.setId(1);

    User user = new User();
    user.setName(name);
    user.setDepartment(dept);
    Example<User> example = Example.of(user);
    List<User> list = userDao.findAll(example);
    return list
}

以上代码首先创建了User对象,设置 查询条件,名称为参数name,部门id为1,通过Example.of构造了此查询。

大部分查询并非完全匹配查询,ExampleMatcher 提供了更多的条件指定.比如以xxx开头的所有用户,则可以使用以下代码构造:

ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("xxx",
    GenericPropertyMatchers.startsWith().ignoreCase());
Example<User> example = Example.of(user, matcher);

资料:Spring Data JPA 实例查询

排序Sort

Sort对象用来指定排序,最简单的Sort对象构造可以传入一个属性名列表(不是数据库列名,是属性名)。默认采用升序排序。

Sort sort = new Sort("id");
//Sort sort = new Sort(Direction.DESC, "id");
return userDao.findAll(sort);

Hibernate 根据Sort构造了排序条件,Sort("id")表示按照id采用默认 升序进行排序

其他Sort的构造方法还包括以下主要的一些:

  • public Sort(String... properties), 按照指定的属性列表升序排序。

  • public Sort(Sort.Direction direction, String... properties), 按照指定属性列表排序,排序由direction指定,direction是一个枚举类型,有Direction.ASCDirection.DESC

  • public Sort(Sort.Order... orders), 可以通过Order静态方法来创建

    • public static Sort.Order asc(String property)

    • public static Sort.Order desc(String property)

分页Page和Pageable

Pageable 接口用于构造翻页查询,PageRequest是其实现类,可以通过提供的工厂方法创建PageRequest:

注意我这边使用的是sring boot 2.0.2 ,jpa版本是2.0.8,新版本与之前版本的操作方法有所不同。

  • public static PageRequest of(int page, int size)

  • public static PageRequest of(int page, int size, Sort sort) - 也可以在PageRequest中加入排序

  • public static PageRequest of(int page, int size, Direction direction, String... properties),或者自定义排序规则

page是从0开始,表示查询页,size指每页的期望行数。

Spring Data翻页查询总是返回Page对象,Page对象提供了以下常用的方法

  • int getTotalPages();, 总的页数

  • long getTotalElements(); - 返回总数

  • List<T> getContent(); - 返回此次查询的结果集

示例:

Public List<User> getAllUsers(int page, int size) {
    PageRequest pageable = PageRequest.of(page, size);
    Page<User> pageObject = userDao.findAll(pageable);
    int totalPage = pageObject.getTotalPages();
    int count = pageObject.getTotalElements();
    return pageObject.getContent()
}

Last updated