복붙노트

[SPRING] 스프링 데이터의 페이지 매김 JPA (한계 및 오프셋)

SPRING

스프링 데이터의 페이지 매김 JPA (한계 및 오프셋)

사용자가 내 쿼리 메서드에서 제한 (반환되는 크기의 크기) 및 오프셋 (반환 된 첫 번째 레코드 / 인덱스)을 지정할 수있게하려고합니다.

다음은 페이징 기능이없는 클래스입니다. 내 사업체 :

@Entity
public Employee {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @Column(name="NAME")
    private String name;

    //getters and setters
}

내 저장소 :

public interface EmployeeRepository extends JpaRepository<Employee, Integer> {

    @Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")
    public List<Employee> findByName(@Param("name") String name);
}

내 서비스 인터페이스 :

public interface EmployeeService {

    public List<Employee> findByName(String name);
}

내 서비스 구현 :

public class EmployeeServiceImpl {

    @Resource
    EmployeeRepository repository;

    @Override
    public List<Employee> findByName(String name) {
        return repository.findByName(name);
    }
}

이제 오프셋 및 제한을 지원하는 페이징 기능을 제공하려는 시도가 있습니다. 내 엔티티 클래스는 동일하게 유지됩니다.

내 "새"저장소는 페이지 가능한 매개 변수를 사용합니다.

public interface EmployeeRepository extends JpaRepository<Employee, Integer> {

    @Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")
    public List<Employee> findByName(@Param("name") String name, Pageable pageable);
}

내 "새로운"서비스 인터페이스는 두 개의 추가 매개 변수를 필요로합니다.

public interface EmployeeService {

    public List<Employee> findByName(String name, int offset, int limit);
}

내 "새로운"서비스 구현 :

public class EmployeeServiceImpl {

    @Resource
    EmployeeRepository repository;

    @Override
    public List<Employee> findByName(String name, int offset, int limit) {
        return repository.findByName(name, new PageRequest(offset, limit);
    }
}

그러나 이것은 내가 원하는 것이 아닙니다. PageRequest는 페이지 및 크기 (페이지 번호 및 페이지 크기)를 지정합니다. 이제 크기를 지정하는 것이 정확히 원하는 것입니다. 그러나 시작 페이지를 지정하고 싶지는 않습니다. # 사용자가 시작 레코드 / 인덱스를 지정할 수있게하려고합니다. 나는 비슷한 것을 원한다.

public List<Employee> findByName(String name, int offset, int limit) {
    TypedQuery<Employee> query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id", Employee.class);
    query.setFirstResult(offset);
    query.setMaxResults(limit);
    return query.getResultList();
}

특히 setFirstResult () 및 setMaxResult () 메서드. 하지만 Employee 저장소 인터페이스를 사용하기 때문에이 방법을 사용할 수 없습니다. (또는 실제로 entityManager를 통해 쿼리를 정의하는 것이 더 낫습니까?) 어쨌든 entityManager를 사용하지 않고 오프셋을 지정하는 방법이 있습니까? 미리 감사드립니다.

해결법

  1. ==============================

    1.아래 코드는 그렇게해야합니다. 나는 내 프로젝트에서 사용하고 대부분의 경우를 테스트했다.

    아래 코드는 그렇게해야합니다. 나는 내 프로젝트에서 사용하고 대부분의 경우를 테스트했다.

    용법:

       Pageable pageable = new OffsetBasedPageRequest(offset, limit);
       return this.dataServices.findAllInclusive(pageable);
    

    및 소스 코드 :

    import org.apache.commons.lang3.builder.EqualsBuilder;
    import org.apache.commons.lang3.builder.HashCodeBuilder;
    import org.apache.commons.lang3.builder.ToStringBuilder;
    import org.springframework.data.domain.AbstractPageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    
    import java.io.Serializable;
    
    /**
    * Created by Ergin
    **/
    public class OffsetBasedPageRequest implements Pageable, Serializable {
    
        private static final long serialVersionUID = -25822477129613575L;
    
        private int limit;
        private int offset;
        private final Sort sort;
    
        /**
         * Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
         *
         * @param offset zero-based offset.
         * @param limit  the size of the elements to be returned.
         * @param sort   can be {@literal null}.
         */
        public OffsetBasedPageRequest(int offset, int limit, Sort sort) {
            if (offset < 0) {
                throw new IllegalArgumentException("Offset index must not be less than zero!");
            }
    
            if (limit < 1) {
                throw new IllegalArgumentException("Limit must not be less than one!");
            }
            this.limit = limit;
            this.offset = offset;
            this.sort = sort;
        }
    
        /**
         * Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
         *
         * @param offset     zero-based offset.
         * @param limit      the size of the elements to be returned.
         * @param direction  the direction of the {@link Sort} to be specified, can be {@literal null}.
         * @param properties the properties to sort by, must not be {@literal null} or empty.
         */
        public OffsetBasedPageRequest(int offset, int limit, Sort.Direction direction, String... properties) {
            this(offset, limit, new Sort(direction, properties));
        }
    
        /**
         * Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
         *
         * @param offset zero-based offset.
         * @param limit  the size of the elements to be returned.
         */
        public OffsetBasedPageRequest(int offset, int limit) {
            this(offset, limit, new Sort(Sort.Direction.ASC,"id"));
        }
    
        @Override
        public int getPageNumber() {
            return offset / limit;
        }
    
        @Override
        public int getPageSize() {
            return limit;
        }
    
        @Override
        public int getOffset() {
            return offset;
        }
    
        @Override
        public Sort getSort() {
            return sort;
        }
    
        @Override
        public Pageable next() {
            return new OffsetBasedPageRequest(getOffset() + getPageSize(), getPageSize(), getSort());
        }
    
        public OffsetBasedPageRequest previous() {
            return hasPrevious() ? new OffsetBasedPageRequest(getOffset() - getPageSize(), getPageSize(), getSort()) : this;
        }
    
    
        @Override
        public Pageable previousOrFirst() {
            return hasPrevious() ? previous() : first();
        }
    
        @Override
        public Pageable first() {
            return new OffsetBasedPageRequest(0, getPageSize(), getSort());
        }
    
        @Override
        public boolean hasPrevious() {
            return offset > limit;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
    
            if (!(o instanceof OffsetBasedPageRequest)) return false;
    
            OffsetBasedPageRequest that = (OffsetBasedPageRequest) o;
    
            return new EqualsBuilder()
                    .append(limit, that.limit)
                    .append(offset, that.offset)
                    .append(sort, that.sort)
                    .isEquals();
        }
    
        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37)
                    .append(limit)
                    .append(offset)
                    .append(sort)
                    .toHashCode();
        }
    
        @Override
        public String toString() {
            return new ToStringBuilder(this)
                    .append("limit", limit)
                    .append("offset", offset)
                    .append("sort", sort)
                    .toString();
        }
    }
    
  2. ==============================

    2.자신의 Pageable을 작성하여이를 수행 할 수 있습니다.

    자신의 Pageable을 작성하여이를 수행 할 수 있습니다.

    이 기본 샘플을 사용해보십시오. 나를 위해 잘 작동합니다.

    public class ChunkRequest implements Pageable {
    
    private int limit = 0;
    private int offset = 0;
    
    public ChunkRequest(int skip, int offset) {
        if (skip < 0)
            throw new IllegalArgumentException("Skip must not be less than zero!");
    
        if (offset < 0)
            throw new IllegalArgumentException("Offset must not be less than zero!");
    
        this.limit = offset;
        this.offset = skip;
    }
    
    @Override
    public int getPageNumber() {
        return 0;
    }
    
    @Override
    public int getPageSize() {
        return limit;
    }
    
    @Override
    public int getOffset() {
        return offset;
    }
    
    @Override
    public Sort getSort() {
        return null;
    }
    
    @Override
    public Pageable next() {
        return null;
    }
    
    @Override
    public Pageable previousOrFirst() {
        return this;
    }
    
    @Override
    public Pageable first() {
        return this;
    }
    
    @Override
    public boolean hasPrevious() {
        return false;
    }
    
    }
    
  3. ==============================

    3.어쩌면 그 대답은 좀 늦을 지 모르지만 나는 똑같은 생각을했습니다. 오프셋 및 제한을 기준으로 현재 페이지를 계산합니다. 오프셋은 제한의 배수라고 "가정"하기 때문에 정확하게 동일하지는 않지만 응용 프로그램이 이에 적합 할 수 있습니다.

    어쩌면 그 대답은 좀 늦을 지 모르지만 나는 똑같은 생각을했습니다. 오프셋 및 제한을 기준으로 현재 페이지를 계산합니다. 오프셋은 제한의 배수라고 "가정"하기 때문에 정확하게 동일하지는 않지만 응용 프로그램이 이에 적합 할 수 있습니다.

    @Override
    public List<Employee> findByName(String name, int offset, int limit) {
        // limit != 0 ;)
        int page = offset / limit;
        return repository.findByName(name, new PageRequest(page, limit);
    }
    

    나는 건축의 변화를 제안 할 것이다. 컨트롤러를 변경하거나 처음에는 가능한 한 페이지 및 제한을 제공하도록 서비스를 호출하는 모든 것을 변경하십시오.

  4. ==============================

    4.스프링 데이터 jpa로는이 작업을 수행 할 수 없습니다. 오프셋이 매우 작은 경우 검색 후 쿼리에서 상위 X 문을 제거하면됩니다.

    스프링 데이터 jpa로는이 작업을 수행 할 수 없습니다. 오프셋이 매우 작은 경우 검색 후 쿼리에서 상위 X 문을 제거하면됩니다.

    그렇지 않으면 페이지 크기를 오프셋으로 정의하고 페이지 + 1에서 시작할 수 있습니다.

  5. ==============================

    5.여기 있습니다 :

    여기 있습니다 :

    public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
    
        @Query(value="SELECT e FROM Employee e WHERE e.name LIKE ?1 ORDER BY e.id offset ?2 limit ?3", nativeQuery = true)
        public List<Employee> findByNameAndMore(String name, int offset, int limit);
    }
    
  6. ==============================

    6.시도해보십시오 :

    시도해보십시오 :

    public interface ContactRepository extends JpaRepository<Contact, Long> 
    {
        @Query(value = "Select c.* from contacts c where c.username is not null order by c.id asc limit ?1,  ?2 ", nativeQuery = true)         
        List<Contact> findContacts(int offset, int limit);        
    }
    
  7. ==============================

    7.같은 시간에 필터링 및 정렬 및 페이징을한다고 가정하십시오. @Query가 당신을 도울 것입니다.

    같은 시간에 필터링 및 정렬 및 페이징을한다고 가정하십시오. @Query가 당신을 도울 것입니다.

        @Query(value = "SELECT * FROM table  WHERE firstname= ?1  or lastname= ?2 or age= ?3 or city= ?4 or "
            + " ORDER BY date DESC OFFSET ?8 ROWS FETCH NEXT ?9 ROWS ONLY" , nativeQuery = true)
    List<JobVacancy> filterJobVacancyByParams(final String firstname, final String lastname,
            final String age, final float city,int offset, int limit);
    
  8. from https://stackoverflow.com/questions/25008472/pagination-in-spring-data-jpa-limit-and-offset by cc-by-sa and MIT license