Перейти к основному содержимому

Ограничение результатов запроса с помощью JPA и Spring Data JPA

· 4 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Введение

В этом руководстве мы узнаем об ограничении результатов запроса с помощью JPA и Spring Data JPA .

Во-первых, мы рассмотрим таблицу, которую мы хотим запросить, а также SQL-запрос, который мы хотим воспроизвести.

Затем мы углубимся в то, как этого добиться с помощью JPA и Spring Data JPA.

Давайте начнем!

2. Тестовые данные

Ниже у нас есть таблица, которую мы будем запрашивать в этой статье.

Вопрос, на который мы хотим ответить, звучит так: «Какое первое занятое место и кто его занимает?»

   | Имя    | Фамилия    | Номер места   | 
| Джилл | Смит | 50 |
| Канун | Джексон | 94 |
| Фред | Блоги | 22 |
| Рики | Бобби | 36 |
| Сия | Колиси | 85 |

3. SQL

С помощью SQL мы могли бы написать запрос, который выглядит примерно так:

SELECT firstName, lastName, seatNumber FROM passengers ORDER BY seatNumber LIMIT 1;

4. Настройка JPA

С JPA нам сначала нужна Entity для сопоставления нашей таблицы:

@Entity
class Passenger {

@Id
@GeneratedValue
@Column(nullable = false)
private Long id;

@Basic(optional = false)
@Column(nullable = false)
private String fistName;

@Basic(optional = false)
@Column(nullable = false)
private String lastName;

@Basic(optional = false)
@Column(nullable = false)
private int seatNumber;

// constructor, getters etc.
}

Далее нам нужен метод, который инкапсулирует наш код запроса, реализованный здесь как PassengerRepositoryImpl#findOrderedBySeatNumberLimitedTo(int limit) :

@Repository
class PassengerRepositoryImpl {

@PersistenceContext
private EntityManager entityManager;

@Override
public List<Passenger> findOrderedBySeatNumberLimitedTo(int limit) {
return entityManager.createQuery("SELECT p FROM Passenger p ORDER BY p.seatNumber",
Passenger.class).setMaxResults(limit).getResultList();
}
}

В нашем методе репозитория мы используем EntityManager для создания запроса , для которого мы вызываем метод setMaxResults() .

Этот вызов Query#setMaxResults в конечном итоге приведет к тому, что оператор limit будет добавлен к сгенерированному SQL:

select
passenger0_.id as id1_15_,
passenger0_.fist_name as fist_nam2_15_,
passenger0_.last_name as last_nam3_15_,
passenger0_.seat_number as seat_num4_15_
from passenger passenger0_ order by passenger0_.seat_number limit ?

5. С Spring Data JPA

Мы также можем сгенерировать наш SQL, используя Spring Data JPA.

5.1. первый или верхний

Один из способов приблизиться к этому — использовать производное имя метода с ключевыми словами first или top.

При желании мы можем указать число в качестве максимального размера результата, который будет возвращен. Если мы его опустим, Spring Data JPA предполагает, что размер результата равен 1.

Поскольку мы хотим знать, какое место было занято первым и кто его занимает, мы можем получить его, опустив номер, двумя способами:

Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();

Если мы ограничимся одним экземпляром результата, как указано выше, мы также можем обернуть результат, используя необязательный :

Optional<Passenger> findFirstByOrderBySeatNumberAsc();
Optional<Passenger> findTopByOrderBySeatNumberAsc();

5.2. Постраничный

В качестве альтернативы мы можем использовать объект Pageable :

Page<Passenger> page = repository.findAll(
PageRequest.of(0, 1, Sort.by(Sort.Direction.ASC, "seatNumber")));

Если мы посмотрим на реализацию JpaRepository по умолчанию, SimpleJpaRepository , мы увидим, что она также вызывает Query#setMaxResults :

protected <S extends T > Page < S > readPage(TypedQuery < S > query, 
Class < S > domainClass, Pageable pageable,
@Nullable Specification < S > spec) {
if (pageable.isPaged()) {
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
}

return PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> {
return executeCountQuery(this.getCountQuery(spec, domainClass));
});
}

5.3. Сравнение

Обе эти альтернативы будут генерировать SQL, который нам нужен, с соглашением о первом и наибольшем преимуществе и конфигурацией предпочтения Pageable : ``

select
passenger0_.id as id1_15_,
passenger0_.fist_name as fist_nam2_15_,
passenger0_.last_name as last_nam3_15_,
passenger0_.seat_number as seat_num4_15_
from passenger passenger0_ order by passenger0_.seat_number asc limit ?

6. Заключение

Ограничение результатов запроса в JPA немного отличается от SQL; мы не включаем ключевое слово limit непосредственно в наш JPQL .

Вместо этого мы просто делаем один вызов метода Query#maxResults или включаем ключевое слово first или top в имя нашего метода Spring Data JPA .

Как всегда, код доступен на GitHub .