Spring Boot应用中能否全局默认设置Hibernate的HINT_PASS_DISTINCT_THROUGH查询提示?
全局配置Hibernate HINT_PASS_DISTINCT_THROUGH的方案
如果你想在Spring Boot应用里给所有带DISTINCT关键字的查询自动加上HINT_PASS_DISTINCT_THROUGH提示,不用逐个配置,有几种靠谱的全局方案:
方法一:直接用Hibernate全局配置属性(推荐,Hibernate 5.4+适用)
从Hibernate 5.4版本开始,官方提供了全局配置项,直接在application.properties或application.yml里加一行配置就能生效:
application.properties格式
spring.jpa.properties.hibernate.query.pass_distinct_through=true
application.yml格式
spring: jpa: properties: hibernate: query: pass_distinct_through: true
这个配置会让所有包含DISTINCT的JPQL/HQL查询自动启用该提示,完全不需要额外代码。
方法二:自定义Spring Data JPA仓库工厂(适配低版本Hibernate或需精细控制)
如果你的Hibernate版本低于5.4,或者需要针对特定仓库做调整,可以通过自定义RepositoryFactoryBean来自动给带DISTINCT的查询加提示:
- 自定义RepositoryFactoryBean和Factory类
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.RepositoryFactorySupport; import javax.persistence.EntityManager; import java.io.Serializable; public class DistinctHintRepositoryFactoryBean<T extends org.springframework.data.repository.Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> { public DistinctHintRepositoryFactoryBean(Class<? extends T> repositoryInterface) { super(repositoryInterface); } @Override protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { return new DistinctHintRepositoryFactory(entityManager); } private static class DistinctHintRepositoryFactory extends org.springframework.data.jpa.repository.support.JpaRepositoryFactory { public DistinctHintRepositoryFactory(EntityManager entityManager) { super(entityManager); } @Override protected javax.persistence.Query createQuery(String queryString, Class<?> resultType) { javax.persistence.Query query = super.createQuery(queryString, resultType); if (queryString.toUpperCase().contains("DISTINCT")) { query.setHint("org.hibernate.query.passDistinctThrough", true); } return query; } @Override protected javax.persistence.Query createCountQuery(String queryString) { javax.persistence.Query query = super.createCountQuery(queryString); if (queryString.toUpperCase().contains("DISTINCT")) { query.setHint("org.hibernate.query.passDistinctThrough", true); } return query; } } }
- 在Spring配置里启用这个自定义工厂
import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @Configuration @EnableJpaRepositories(repositoryFactoryBeanClass = DistinctHintRepositoryFactoryBean.class) public class JpaConfig { }
这种方式会覆盖Spring Data JPA生成的所有查询(包括自动生成和@Query注解定义的),自动给带DISTINCT的查询加上提示。
方法三:自定义Hibernate拦截器(更底层的控制)
如果需要更底层的干预,可以写一个Hibernate Interceptor,在查询执行前检查并添加提示:
- 实现拦截器
import org.hibernate.EmptyInterceptor; import org.hibernate.event.spi.QueryEvent; import org.hibernate.event.spi.QueryEventListener; public class DistinctQueryHintInterceptor extends EmptyInterceptor implements QueryEventListener { @Override public void onQueryPrepare(QueryEvent event) { String queryString = event.getQueryString(); if (queryString != null && queryString.toUpperCase().contains("DISTINCT")) { event.getQuery().setHint("org.hibernate.query.passDistinctThrough", true); } } }
- 注册拦截器到Spring配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import javax.persistence.EntityManagerFactory; import java.util.Properties; @Configuration public class HibernateConfig { @Bean public DistinctQueryHintInterceptor distinctQueryHintInterceptor() { return new DistinctQueryHintInterceptor(); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactory emf) { LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setEntityManagerFactory(emf); Properties jpaProps = new Properties(); jpaProps.put("hibernate.session_factory.interceptor", distinctQueryHintInterceptor()); factory.setJpaProperties(jpaProps); return factory; } }
这种方式对所有通过Hibernate执行的查询生效,包括原生SQL查询(只要包含DISTINCT)。
内容的提问来源于stack exchange,提问作者Guillaume Delafosse
相关产品推荐
相关产品推荐

