Spring boot Spring数据JPA分页HH000104

Spring boot Spring数据JPA分页HH000104,spring-boot,hibernate,jpa,spring-data-jpa,Spring Boot,Hibernate,Jpa,Spring Data Jpa,我得到了这个存储库代码: @Query(value = "select distinct r from Reference r " + "inner join fetch r.persons " + "left outer join fetch r.categories " + "left outer join fetch r.keywords " +

我得到了这个存储库代码:

@Query(value = "select distinct r from Reference r " +
        "inner join fetch r.persons " +
        "left outer join fetch r.categories " +
        "left outer join fetch r.keywords " +
        "left outer join fetch r.parentReferences",
        countQuery = "select count(distinct r.id) from Reference r " +
                "inner join r.persons " +
                "left outer join r.categories " +
                "left outer join r.keywords " +
                "left outer join r.parentReferences")
Page<Reference> findsAllRelevantEntries(Pageable pageable);
存储库代码封装在此处未显示的服务方法中。它(服务方法)只是将调用从服务封送到存储库并返回

此外,生成的sql查询不会生成
limit
子句。尽管它确实引发了两个疑问

一个用于计数,另一个用于提取所有记录。
因此,它将获取所有记录并在内存中应用分页。
这会导致查询执行非常缓慢

如何使用此查询进行分页

编辑

我知道这里经常建议将此作为解决方案:

有没有办法用Spring数据JPA实现分页? 我不想硬连线
实体管理器,我也不想

基本TransformerAdapter扩展代码

我自己找到了一个解决方法。基于此:

首先:通过分页获取ID:

@Query(value = "select distinct r.id from Reference r " +
        "inner join r.persons " +
        "left outer join r.categories " +
        "left outer join r.keywords " +
        "left outer join r.parentReferences " +
        "order by r.id",
        countQuery = "select count(distinct r.id) from Reference r " +
                "inner join r.persons " +
                "left outer join r.categories " +
                "left outer join r.keywords " +
                "left outer join r.parentReferences " +
                "order by r.id")
Page<UUID> findsAllRelevantEntriesIds(Pageable pageable);
注意:
我得到了一个
列表我自己找到了一个解决办法。基于此:

首先:通过分页获取ID:

@Query(value = "select distinct r.id from Reference r " +
        "inner join r.persons " +
        "left outer join r.categories " +
        "left outer join r.keywords " +
        "left outer join r.parentReferences " +
        "order by r.id",
        countQuery = "select count(distinct r.id) from Reference r " +
                "inner join r.persons " +
                "left outer join r.categories " +
                "left outer join r.keywords " +
                "left outer join r.parentReferences " +
                "order by r.id")
Page<UUID> findsAllRelevantEntriesIds(Pageable pageable);
注意:
我得到了一个
List方法,首先获取ID,然后执行主查询,但效率不是很高。我认为这是一个完美的用例

Blaze Persistence是JPA之上的查询生成器,它支持JPA模型之上的许多高级DBMS功能。它附带的分页支持可以处理您可能遇到的所有问题

它还具有Spring数据集成,因此您可以像现在一样使用相同的代码,您只需添加依赖项并进行设置:

Blaze Persistence有许多不同的分页策略,您可以对其进行配置。默认策略是将ID查询内联到主查询中。大概是这样的:

select r 
from Reference r 
inner join r.persons
left join fetch r.categories 
left join fetch r.keywords
left join fetch r.parentReferences 
where r.id IN (
  select r2.id
  from Reference r2
  inner join r2.persons
  order by ...
  limit ...
)
order by ...

先获取ID,然后执行主查询的方法很有效,但效率不高。我认为这是一个完美的用例

Blaze Persistence是JPA之上的查询生成器,它支持JPA模型之上的许多高级DBMS功能。它附带的分页支持可以处理您可能遇到的所有问题

它还具有Spring数据集成,因此您可以像现在一样使用相同的代码,您只需添加依赖项并进行设置:

Blaze Persistence有许多不同的分页策略,您可以对其进行配置。默认策略是将ID查询内联到主查询中。大概是这样的:

select r 
from Reference r 
inner join r.persons
left join fetch r.categories 
left join fetch r.keywords
left join fetch r.parentReferences 
where r.id IN (
  select r2.id
  from Reference r2
  inner join r2.persons
  order by ...
  limit ...
)
order by ...

您可以使用基于双查询方法的通用/可重用方法

一个SQL查询用于检索实体的
ID
,第二个查询使用
IN
谓词,包括第二个查询中的
ID

实现自定义Spring数据JPA执行器:

@NoRepositoryBean
public interface AsimioJpaSpecificationExecutor<E, ID extends Serializable> extends JpaSpecificationExecutor<E> {

  Page<ID> findEntityIds(Pageable pageable);
}


public class AsimioSimpleJpaRepository<E, ID extends Serializable> extends SimpleJpaRepository<E, ID>
        implements AsimioJpaSpecificationExecutor<E, ID> {

  private final EntityManager entityManager;
  private final JpaEntityInformation<E, ID> entityInformation;

  public AsimioSimpleJpaRepository(JpaEntityInformation<E, ID> entityInformation, EntityManager entityManager) {
    super(entityInformation, entityManager);
    this.entityManager = entityManager;
    this.entityInformation = entityInformation;
  }

  @Override
  public Page<ID> findEntityIds(Pageable pageable) {
    CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
    CriteriaQuery<ID> criteriaQuery = criteriaBuilder.createQuery(this.entityInformation.getIdType());
    Root<E> root = criteriaQuery.from(this.getDomainClass());

    // Get the entities ID only
    criteriaQuery.select((Path<ID>) root.get(this.entityInformation.getIdAttribute()));

    // Update Sorting
    Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
    if (sort.isSorted()) {
      criteriaQuery.orderBy(toOrders(sort, root, criteriaBuilder));
    }

    TypedQuery<ID> typedQuery = this.entityManager.createQuery(criteriaQuery);

    // Update Pagination attributes
    if (pageable.isPaged()) {
      typedQuery.setFirstResult((int) pageable.getOffset());
      typedQuery.setMaxResults(pageable.getPageSize());
    }

    return PageableExecutionUtils.getPage(typedQuery.getResultList(), pageable,
      () -> executeCountQuery(this.getCountQuery(null, this.getDomainClass())));
  }

  protected static long executeCountQuery(TypedQuery<Long> query) {
    Assert.notNull(query, "TypedQuery must not be null!");

    List<Long> totals = query.getResultList();
    long total = 0L;

    for (Long element : totals) {
      total += element == null ? 0 : element;
    }

    return total;
  }
}
@NoRepositoryBean
公共接口AsimioJpaSpecificationExecutor扩展了JpaSpecificationExecutor{
页面FindentialId(可分页);
}
公共类AsimioSimpleParepository扩展了SimpleParepository
实现AsimioJpaSpecificationExecutor{
私人最终实体管理人实体管理人;
私人最终JPA实体信息实体信息;
公共asimiosimpleparepository(JpaEntityInformation entityInformation,EntityManager EntityManager){
超级(实体信息、实体管理器);
this.entityManager=entityManager;
this.entityInformation=entityInformation;
}
@凌驾
公共页面FindentialId(可分页){
CriteriaBuilder CriteriaBuilder=this.entityManager.getCriteriaBuilder();
CriteriaQuery CriteriaQuery=criteriaBuilder.createQuery(this.entityInformation.getIdType());
Root=criteriaQuery.from(this.getDomainClass());
//仅获取实体ID
select((路径)root.get(this.entityInformation.getIdAttribute());
//更新排序
Sort Sort=pageable.ispage()?pageable.getSort():Sort.unsorted();
if(sort.isSorted()){
orderBy(toOrders(排序、根、criteriaBuilder));
}
TypedQuery TypedQuery=this.entityManager.createQuery(criteriaQuery);
//更新分页属性
if(pageable.ispage()){
typedQuery.setFirstResult((int)pageable.getOffset());
typedQuery.setMaxResults(pageable.getPageSize());
}
返回PageableExecutionUtils.getPage(typedQuery.getResultList(),可分页,
()->executeCountQuery(this.getCountQuery(null,this.getDomainClass()));
}
受保护的静态长执行计数查询(TypedQuery查询){
notNull(查询,“TypedQuery不能为null!”);
List totals=query.getResultList();
总长度=0升;
用于(长元素:总计){
合计+=元素==null?0:元素;
}
返回总数;
}
}

您可以在

上阅读更多内容。您可以使用基于双查询方法的通用/可重用方法

一个SQL查询用于检索实体的
ID
,第二个查询使用
IN
谓词,包括第二个查询中的
ID

实现自定义Spring数据JPA执行器:

@NoRepositoryBean
public interface AsimioJpaSpecificationExecutor<E, ID extends Serializable> extends JpaSpecificationExecutor<E> {

  Page<ID> findEntityIds(Pageable pageable);
}


public class AsimioSimpleJpaRepository<E, ID extends Serializable> extends SimpleJpaRepository<E, ID>
        implements AsimioJpaSpecificationExecutor<E, ID> {

  private final EntityManager entityManager;
  private final JpaEntityInformation<E, ID> entityInformation;

  public AsimioSimpleJpaRepository(JpaEntityInformation<E, ID> entityInformation, EntityManager entityManager) {
    super(entityInformation, entityManager);
    this.entityManager = entityManager;
    this.entityInformation = entityInformation;
  }

  @Override
  public Page<ID> findEntityIds(Pageable pageable) {
    CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
    CriteriaQuery<ID> criteriaQuery = criteriaBuilder.createQuery(this.entityInformation.getIdType());
    Root<E> root = criteriaQuery.from(this.getDomainClass());

    // Get the entities ID only
    criteriaQuery.select((Path<ID>) root.get(this.entityInformation.getIdAttribute()));

    // Update Sorting
    Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
    if (sort.isSorted()) {
      criteriaQuery.orderBy(toOrders(sort, root, criteriaBuilder));
    }

    TypedQuery<ID> typedQuery = this.entityManager.createQuery(criteriaQuery);

    // Update Pagination attributes
    if (pageable.isPaged()) {
      typedQuery.setFirstResult((int) pageable.getOffset());
      typedQuery.setMaxResults(pageable.getPageSize());
    }

    return PageableExecutionUtils.getPage(typedQuery.getResultList(), pageable,
      () -> executeCountQuery(this.getCountQuery(null, this.getDomainClass())));
  }

  protected static long executeCountQuery(TypedQuery<Long> query) {
    Assert.notNull(query, "TypedQuery must not be null!");

    List<Long> totals = query.getResultList();
    long total = 0L;

    for (Long element : totals) {
      total += element == null ? 0 : element;
    }

    return total;
  }
}
@NoRepositoryBean
公共接口AsimioJpaSpecificationExecutor扩展了JpaSpecificationExecutor{
页面FindentialId(可分页);
}
公共类AsimioSimpleParepository扩展了SimpleParepository
实现AsimioJpaSpecificationExecutor{
私人最终实体管理人实体管理人;
私人最终JPA实体信息实体信息;
公共asimiosimpleparepository(JpaEntityInformation entityInformation,EntityManager EntityManager){
超级(实体信息、实体管理器);
this.entityManager=entityManager;
this.entityInformation=entityInformation;
}
@凌驾
公共页面FindentialId(可分页){
CriteriaBuilder CriteriaBuilder=this.entityManager.getCriteriaBui