1、简介 {#1简介}
本文将带你了解 Spring Data JPA 中 Query Hint (查询提示)的功能、基本原理以及如何有效地应用它们。
这些提示有助于优化数据库查询,并通过影响优化器的决策过程来改善应用性能。
2、理解 Query Hint {#2理解-query-hint}
Spring Data JPA 中的 Query Hint 是一种强大的工具,可帮助优化数据库查询并提高应用性能。与直接控制执行不同,Query Hint 会影响优化器(Optimizer)的决策过程。
在 Spring Data JPA 中,可以在 org.hibernate.annotations
包中找到这些 Hint,同时还有与 Hibernate 相关的各种注解和类。需要注意的是,这些 Hint 的解释和执行通常取决于底层持久化层实现(Persistence Provider),如 Hibernate 或 EclipseLink,因此它们是特定于厂商的。
3、使用 Query Hint {#3使用-query-hint}
Spring Data JPA 提供了多种利用 Query Hint 优化数据库查询的方法。
3.1、基于注解的配置 {#31基于注解的配置}
Spring Data JPA 提供了一种使用注解为 JPA 查询添加 Query Hint 的简便方法。通过 @QueryHints
注解,可以指定用于生成 SQL 查询的 JPA @QueryHint
数组。
示例如下,设置了 JDBC fetch size Hint,以限制结果返回的大小:
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@QueryHints(value = { @QueryHint(name = "org.hibernate.fetchSize", value = "50") })
List<Employee> findByGender(String gender);
}
如上,在 EmployeeRepository
接口的 findByGender()
方法中添加了 @QueryHints
注解,以控制一次获取的实体数量。
此外,还可以在 Repository 级别应用 @QueryHints
注解,以影响 Repository 中的所有查询:
@Repository
@QueryHints(value = { @QueryHint(name = "org.hibernate.fetchSize", value = "50") })
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
// Repository 方法。。。
}
此操作可确保指定的 Query Hint 适用于 EmployeeRepository
接口中的所有查询,从而促进整个 Repository 查询的一致性。
3.2、编程式配置 Query Hint {#32编程式配置-query-hint}
除了基于注解和动态的方法外,还可以使用 EntityManager
对象以编程方式配置 Query Hint。这种方法提供了对 Query Hint 配置的细粒度控制。下面是一个以编程方式设置自定义 Hint 的示例:
@PersistenceContext
private EntityManager entityManager;
@Override
List<Employee> findRecentEmployees(int limit, boolean readOnly) {
Query query = entityManager.createQuery("SELECT e FROM Employee e ORDER BY e.joinDate DESC", Employee.class)
.setMaxResults(limit)
.setHint("org.hibernate.readOnly", readOnly);
return query.getResultList();
}
如上,传递了一个 boolean
标志作为参数,用于指示应将 Hint 设置为 true
还是 false
。这种灵活性使我们可以根据运行时的条件调整查询行为。
3.3、在实体中定义命名查询(Named Query) {#33在实体中定义命名查询named-query}
Query Hint 可以直接在实体类中使用 @NamedQuery
注解来应用。这样,就可以在定义命名查询的同时定义特定的 Hint。如下:
@Entity
@NamedQuery(name = "selectEmployee", query = "SELECT e FROM Employee e",
hints = @QueryHint(name = "org.hibernate.fetchSize", value = "50"))
public class Employee {
// Entity 属性和方法
}
一旦在实体类中定义了命名查询 selectEmployee
和相关 Hint,就可以使用 EntityManager
的 createNamedQuery()
方法来调用:
List<Employee> employees = em.createNamedQuery("selectEmployee").getResultList();
4、Query Hint 使用场景 {#4query-hint-使用场景}
Query Hint 可用于各种情况,以优化查询性能。下面是一些常见的使用案例。
4.1、超时控制 {#41超时控制}
在查询可能长时间运行的情况下,实施有效的超时管理策略变得至关重要。通过使用 javax.persistence.query.timeout
Hint,为查询设置最长执行时间。这种做法可确保查询不会超过指定的时间阈值。
该 Hint 接受以毫秒为单位的值,如果查询时间超过限制,就会抛出 LockTimeoutException
。
示例如下,设置了 5000 毫秒的超时:
@QueryHints(value = {@QueryHint(name = "javax.persistence.query.timeout<em>"</em>, value = "5000")})
List<Employee> findActiveEmployees(long inactiveDaysThreshold);
4.2、缓存查询结果 {#42缓存查询结果}
可以使用 jakarta.persistence.cache.retrieveMode
Hint 来启用查询结果的缓存。当设置为 USE
时,JPA 会首先尝试从缓存中检索实体,然后才会访问数据库。当设置为 BYPASS
时,JPA 会忽略缓存并直接从数据库获取实体。
此外,还可以使用 jakarta.persistence.cache.storeMode
来指定 JPA 在二级缓存中存储实体的处理方式。当设置为 USE
时,JPA 会向缓存中添加实体并更新现有实体。BYPASS
模式指示 Hibernate 只更新缓存中的现有实体,而不添加新实体。最后,REFRESH
模式会在检索缓存中的实体前刷新它们,确保缓存数据是最新的。
这些 Hint 的用法如下:
@QueryHints(value = {
@QueryHint(name = "jakarta.persistence.cache.retrieveMode", value = "USE"),
@QueryHint(name = "jakarta.persistence.cache.storeMode", value = "USE")
})
List<Employee> findEmployeesByName(String name);
在检索模式(retrieveMode
)和存储模式(storeMode
)都被配置为 USE
的情况下,Hibernate 在检索和存储实体时都会积极利用二级缓存。
4.3、优化查询执行计划 {#43优化查询执行计划}
Query Hint 可用于影响数据库优化器生成的执行计划。例如,当不需要修改数据时,可以使用 org.hibernate.readOnly
提示来表示查询是只读的:
@QueryHints(@QueryHint(name = "org.hibernate.readOnly", value = "true"))
User findByUsername(String username);
4.4、自定义 SQL 注释 {#44自定义-sql-注释}
org.hibernate.comment
Hint 允许在查询中添加自定义 SQL 注释,从而有助于查询分析和调试。当我们想在生成的 SQL 语句中提供上下文或注释时,这一功能尤其有用。
示例如下:
@QueryHints(value = { @QueryHint(name = "org.hibernate.comment", value = "Retrieve employee older than specified age\"") })
List findByAgeGreaterThan(int age);
5、总结 {#5总结}
本文介绍了在 Spring Data JPA 中 Query Hint(查询提示)的重要性以及它们对优化数据库查询以提升应用性能的重要影响。还介绍了多种技术,包括基于注解的配置和直接的 JPQL 操作,来有效地应用 Query Hint。
Ref:https://www.baeldung.com/spring-data-jpa-query-hints