Spring Data JPA 检索最大值(Max Value)
1、简介
本文将带你了解如何使用 Spring Data JPA 检索数据列中的最大值(Max Value)。
2、示例
首先,添加 spring-boot-starter-data-jpa 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
然后,定义一个简单的 Employee
实体表示员工:
@Entity
public class Employee {
@Id
@GeneratedValue
private Integer id;
private String name;
private Long salary; // 工资
// 构造函数、Getter、Setter 方法省略
}
接下来,看看有哪些方法可以检索出所有员工中薪水(salary
)列的最大值。
3、使用 Repository 的派生查询
Spring Data JPA 提供了一个强大的机制,可以使用 Repository 方法来定义自定义查询。其中之一是派生查询,它允许我们通过声明方法名来实现SQL查询。
创建 Employee
实体类的 Repository 接口:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
Optional<Employee> findTopByOrderBySalaryDesc();
}
如上,我们实现了一个方法 findTopByOrderBySalaryDesc
,该方法使用查询派生机制生成相应的 SQL。根据方法名,它将按照工资(salary
)降序对所有员工进行排序,然后返回第一个员工,即工资最高的员工。
该方法会返回一个加载了所有属性的实体。如果我们只想检索一个工资(salary
)值,可以使用投影查询:
创建 EmployeeSalary
投影接口:
public interface EmployeeSalary {
Long getSalary();
}
修改 Repository
方法:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
Optional<EmployeeSalary> findTopSalaryByOrderBySalaryDesc();
}
如果只需要检索部分列的数据,投影查询非常有用。
4、使用 JPQL 查询
另一种方法是使用 @Query
注解,直接在 Repository 接口中定义自定义 JPQL(Java Persistence Query Language)查询。
实现 JQPL 查询,以获取最高工资(salary
)值:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query("SELECT MAX(e.salary) FROM Employee e")
Optional<Long> findTopSalaryJQPL();
}
与上文一样,该方法会返回所有员工中最高的工资(salary
)值。此外,JPQ 仅仅检索了 MAX(e.salary)
单列值,所以不需要投影查询。
5、使用原生 SQL 查询
在上例中,我们使用了 @Query
注解。这种方法还允许我们直接使用原生查询编写原始 SQL。
使用原生查询实现相同的效果:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query(value = "SELECT MAX(salary) FROM Employee",
nativeQuery = true) // 表示使用的是原生的 SQL 查询
Optional<Long> findTopSalaryNative();
}
该解决方案与 JPQL 类似,使用原生查询可以充分利用特定的 SQL 功能或优化。
6、使用默认的 Repository 方法
还可以使用自定义 Java 代码来查询最大值。
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
default Optional<Long> findTopSalaryCustomMethod() {
return findAll().stream()
.map(Employee::getSalary)
.max(Comparator.naturalOrder());
}
}
如上,添加了一个新的默认方法。使用内置的 findAll()
方法检索所有 Employee
实体,然后对其进行 Stream 处理,并找出最高的工资(salary
)。与以前的方法不同,所有过滤逻辑都发生在应用层,而不是数据库(如果数据量很大的话,这种方法就不适用了)。
7、使用分页
Spring Data JPA 支持分页和排序功能,可以使用它来查找员工的最高工资(salary
)。
这种方式不需要实现任何自定义方法,或者是继承某个 Repository:
public Optional<Long> findTopSalary() {
return findAll(PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "salary")))
.stream()
.map(Employee::getSalary)
.findFirst();
}
我们知道,PagingAndSortingRepository
接口为 Pageable
和 Sort
类型提供了额外支持。因此,JpaRepository
中内置的 findAll()
方法也可以接受这些参数。
8、使用 Criteria API
Spring Data JPA 还提供了 Criteria
API。这是一种编程式的查询构建方法,是一种更加动态和类型安全的方法,可在不使用原始 SQL 的情况下构建复杂的查询。
首先,将 EntityManager
Bean 注入 Service,然后创建一个方法,使用 Criteria API 查找最高工资(salary
):
@Service
public class EmployeeMaxValueService {
@Autowired
private EntityManager entityManager;
public Optional<Long> findMaxSalaryCriteriaAPI() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<Employee> root = query.from(Employee.class);
query.select(cb.max(root.get("salary")));
TypedQuery<Long> typedQuery = entityManager.createQuery(query);
return Optional.ofNullable(typedQuery.getSingleResult());
}
}
如上,首先从注入的 EntityManager
Bean 获取一个 CriteriaBuilder
实例。然后,创建一个 CriteriaBuilder
来指定结果类型,并创建一个 Root
来定义 FROM
子句。最后,SELECT 工资(salary
)字段的最大值并执行查询。
不过,这种方法比前一种更复杂。
9、总结
本文介绍了使用 Spring Data JPA 查找列最大值(Max Value)的各种方法,包括使用派生查询、JPQL 查询、原生 SQL 查询以及 Criteria API 查询。
Ref:https://www.baeldung.com/spring-data-jpa-max-value