1. 概述
本文将深入探讨 JPA 实现数据排序的各种方式,涵盖基础用法到高级场景。
2. 使用 JPA/JQL API 排序
通过 JQL 排序的核心是 Order By
子句,简单粗暴:
String jql = "Select f from Foo as f order by f.id";
Query query = entityManager.createQuery(jql);
JPA 会生成对应的 原生 SQL 语句:
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.id
⚠️ 注意:JQL 中的 SQL 关键字不区分大小写,但实体名和属性名区分大小写。
2.1. 设置排序方向
默认升序排序,但可显式指定。支持 asc
(升序)和 desc
(降序):
String jql = "Select f from Foo as f order by f.id desc";
Query sortQuery = entityManager.createQuery(jql);
生成的 SQL 查询 会包含排序方向:
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.id desc
2.2. 多属性排序
在 order by
子句中添加多个属性即可实现多级排序:
String jql = "Select f from Foo as f order by f.name asc, f.id desc";
Query sortQuery = entityManager.createQuery(jql);
SQL 查询 会包含所有排序条件:
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc, foo0_.id desc
2.3. NULL 值排序优先级
数据库对 NULL 的默认排序规则各不相同,可通过 NULLS FIRST
或 NULLS LAST
自定义:
Query sortQuery = entityManager.createQuery(
"Select f from Foo as f order by f.name desc NULLS LAST");
生成的 SQL 会包含 NULL 处理逻辑(第3行):
Hibernate: select foo0_.id as id1_4_, foo0_.BAR_ID as BAR_ID2_4_,
foo0_.bar_Id as bar_Id2_4_, foo0_.name as name3_4_, from Foo foo0_ order
by case when foo0_.name is null then 1 else 0 end, foo0_.name desc
2.4. 一对多关系排序
以 Bar
实体包含 Foo
集合为例,需同时排序父实体和子集合:
- 排序子集合:在
Bar
实体中使用@OrderBy
注解:@OrderBy("name ASC") List<Foo> fooList;
- 排序父实体:
String jql = "Select b from Bar as b order by b.id"; Query barQuery = entityManager.createQuery(jql); List<Bar> barList = barQuery.getResultList();
✅ @OrderBy
注解是可选的,此处用于强制排序 Foo
集合。
实际执行的 SQL 查询:
Hibernate: select bar0_.id as id1_0_, bar0_.name as name2_0_ from Bar bar0_ order by bar0_.id
Hibernate:
select foolist0_.BAR_ID as BAR_ID2_0_0_, foolist0_.id as id1_4_0_,
foolist0_.id as id1_4_1_, foolist0_.BAR_ID as BAR_ID2_4_1_,
foolist0_.bar_Id as bar_Id2_4_1_, foolist0_.name as name3_4_1_
from Foo foolist0_
where foolist0_.BAR_ID=? order by foolist0_.name asc
第一条查询排序父实体 Bar
,第二条查询排序其关联的 Foo
集合。
3. 使用 JPA Criteria API 排序
JPA Criteria API 的 orderBy
方法可一站式设置 排序方向 和 排序属性:
orderBy(CriteriaBuilder.asc)
:升序orderBy(CriteriaBuilder.desc)
:降序
每个 Order
实例通过 CriteriaBuilder
的 asc
/desc
方法创建:
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")));
⚠️ get()
方法的参数区分大小写,需与属性名完全匹配。
与 JQL 不同,Criteria API 强制显式指定排序方向。上述代码生成 SQL:
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc
3.1. 多属性排序
为每个排序属性创建 Order
实例并传入 orderBy
:
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")),
criteriaBuilder.desc(from.get("id")));
对应的 SQL 查询:
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc, foo0_.id desc
4. 总结
本文系统梳理了 JPA 的排序方案,从基础实体到一对多关系场景。这些方法将排序压力转移至数据库层,是高效处理数据排序的实用技巧。
完整实现代码可在 GitHub 项目 中获取(Maven 项目,可直接导入运行)。