В этом уроке я покажу вам, как использовать репозиторий JPA для поиска по нескольким полям. В конце вы узнаете, как фильтровать по нескольким столбцам, используя 3 способа: производный запрос, JPQL и собственный запрос.

Этот учебник изначально от Bezkoder:

Обзор

Для запроса данных из базы данных с помощью настраиваемых методов фильтрации Spring Data JPA поддерживает несколько способов:

  • Производный запрос: JPA создает SQL-запросы на основе метода поиска и выполняет запрос за кулисами.
List<Tutorial> findAll();

List<Tutorial> findByTitleContainingIgnoreCase(String title);
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • JPQL: вдохновлен SQL. По синтаксису он напоминает SQL-запросы, но работает с объектами сущностей JPA, хранящимися в реляционной базе данных, а не напрямую с таблицами базы данных.
@Query("SELECT t FROM Tutorial t")
List<Tutorial> findAll();

@Query("SELECT t FROM Tutorial t WHERE t.published=true")
List<Tutorial> findByPublished();
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • Собственный запрос: фактические SQL-запросы, которые можно обрабатывать непосредственно с объектами и таблицами базы данных.
@Query(value = "SELECT * FROM tutorials", nativeQuery = true)
List<Tutorial> findAllNative();

@Query(value = "SELECT * FROM tutorials t WHERE t.published=true", nativeQuery = true)
List<Tutorial> findByPublishedNative();
Войти в полноэкранный режим

Выйти из полноэкранного режима

Для получения более подробной информации и примеров о каждом типе, пожалуйста, посетите:

Продолжим создавать проект, использующий репозиторий JPA с методами поиска по нескольким столбцам.

Фильтр JPA по нескольким столбцам

Технологии

  • Ява 8
  • Spring Boot 2 (с Spring Data JPA)
  • MySQL/PostgreSQL/H2 (встроенная база данных)
  • Мавен 3.8.1

Структура проекта

пример jpa-findby-multiple-fields

Позвольте мне объяснить это кратко.

  • Tutorial класс модели данных соответствует сущности и таблице учебники.
  • TutorialRepository это интерфейс, который расширяет JpaРепозиторий для методов filter/findby. Он будет автоматически подключен в SpringBootQueryExampleApplication.
  • SpringBootQueryExampleApplication является SpringBootApplication который реализует CommandLineRunner. Мы будем использовать TutorialRepository для запуска методов запроса здесь.
  • Конфигурация источника данных Spring, JPA и Hibernate в приложение.свойства.
  • пом.xml содержит зависимости для Spring Boot и базы данных MySQL/PostgreSQL/H2.

Создать и настроить проект Spring Boot

Использовать Весенний веб-инструмент или ваш инструмент разработки (Набор инструментов Springзатмение, Интеллидж) для создания проекта Spring Boot.

Затем откройте пом.xml и добавьте эти зависимости:

<!-- web for access H2 database UI -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Нам также нужно добавить еще одну зависимость.

  • Если вы хотите использовать MySQL:
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
Войти в полноэкранный режим

Выйти из полноэкранного режима

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • или же Н2 (встроенная база данных):
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Настройка источника данных Spring, JPA, Hibernate

В папке src/main/resources откройте application.properties и напишите эти строки.

spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false
spring.datasource.username= root
spring.datasource.password= 123456

spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto= update
Войти в полноэкранный режим

Выйти из полноэкранного режима

spring.datasource.url= jdbc:postgresql://localhost:5432/testdb
spring.datasource.username= postgres
spring.datasource.password= 123

spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation= true
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.PostgreSQLDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto= update
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • spring.datasource.username & spring.datasource.password свойства такие же, как и при установке вашей базы данных.
  • Spring Boot использует Hibernate для реализации JPA, настраиваем MySQL5InnoDBDialect для MySQL или PostgreSQLDialect для PostgreSQL
  • spring.jpa.hibernate.ddl-auto используется для инициализации базы данных. Мы устанавливаем значение update значение, чтобы в базе данных автоматически создавалась таблица, соответствующая заданной модели данных. Любое изменение модели также приведет к обновлению таблицы. Для производства это свойство должно быть validate.
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto= update

spring.h2.console.enabled=true
# default path: h2-console
spring.h2.console.path=/h2-ui
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • spring.datasource.url: jdbc:h2:mem:[database-name] для базы данных в памяти и jdbc:h2:file:[path/database-name] для дисковой базы данных.
  • Мы настраиваем H2Dialect для базы данных H2
  • spring.h2.console.enabled=true говорит Spring запустить инструмент администрирования базы данных H2, и вы можете получить доступ к этому инструменту в браузере: .
  • spring.h2.console.path=/h2-ui для URL-адреса консоли H2, поэтому URL-адрес по умолчанию изменится на http://localhost:8080/h2-ui.

Создать сущность

В модель пакет, мы определяем Tutorial учебный класс.

Туториал имеет следующие поля: id, название, уровень, описание, опубликовано, createdAt.

модель/Учебник.java

package com.bezkoder.spring.jpa.query.model;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "tutorials")
public class Tutorial {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String title;

  private String description;

  private int level;

  private boolean published;

  @Temporal(TemporalType.TIMESTAMP)
  private Date createdAt;

  public Tutorial() {

  }

  public Tutorial(String title, String description, int level, boolean published, Date createdAt) {
    this.title = title;
    this.description = description;
    this.level = level;
    this.published = published;
    this.createdAt = createdAt;
  }

  // getters and setters
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • @Entity аннотация указывает, что класс является постоянным классом Java.
  • @Table аннотация предоставляет таблицу, которая отображает этот объект.

  • @Id аннотация предназначена для первичного ключа.

  • @GeneratedValue аннотация используется для определения стратегии генерации первичного ключа.

  • @Temporal аннотация преобразует туда и обратно между отметкой времени и java.util.Date или отметка времени во времени. Например, @Temporal(TemporalType.DATE) отбрасывает значение времени и сохраняет только дату.

@Temporal(TemporalType.DATE)
private Date createdAt;
Войти в полноэкранный режим

Выйти из полноэкранного режима

Репозиторий JPA Поиск с помощью методов нескольких столбцов

Предположим, что у нас уже есть учебники такая таблица:

jpa-найти-по-несколько-столбцов-пример

Давайте создадим репозиторий для взаимодействия с базой данных.
В хранилище упаковать, создать TutorialRepository интерфейс, расширяющий JpaRepository.

хранилище/TutorialRepository.java

package com.bezkoder.spring.jpa.query.repository;

import com.bezkoder.spring.jpa.query.model.Tutorial;

public interface TutorialRepository extends JpaRepository<Tutorial, Long> {

}
Войти в полноэкранный режим

Выйти из полноэкранного режима

В этом интерфейсе мы напишем JPA-запросы для фильтрации данных из базы данных.

Поиск по нескольким полям с использованием производного запроса

Для нескольких полей/нескольких столбцов мы можем использовать And, Or ключевые слова между полями/столбцами.
Обратите внимание, что вы можете конкатенировать столько And/Or как хочешь.

List<Tutorial> findByLevelAndPublished(int level, boolean isPublished);

List<Tutorial> findByTitleOrDescription(String title, String description);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Результат:

tutorials = tutorialRepository.findByLevelAndPublished(3, true);
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=3, title=Hibernate, description=Hibernate ORM Description, level=3, published=true, createdAt=2022-04-26 00:00:00.0]
Tutorial [id=5, title=Spring JPA, description=Spring Data JPA Description, level=3, published=true, createdAt=2022-05-19 00:00:00.0]
*/

tutorials = tutorialRepository.findByTitleOrDescription("Hibernate", "Spring Data Description");
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=3, title=Hibernate, description=Hibernate ORM Description, level=3, published=true, createdAt=2022-04-26 00:00:00.0]
*/
Войти в полноэкранный режим

Выйти из полноэкранного режима

Мы можем выполнить запрос SQL LIKE со следующими ключевыми словами:

  • Like: где x.field как параметр
  • NotLike: где x.field не похож на param
  • StartingWith: где x.field как %param (с добавленным %)
  • EndingWith: где x.field как param% (с добавленным %)
  • Containing: где x.field как %param% (обернутый в %)

Для запроса, нечувствительного к регистру, в SQL мы можем указать все заглавные или строчные буквы, а затем сравнить со значениями запроса.
Spring JPA предоставляет IgnoreCase ключевое слово, чтобы сделать это с производным запросом.

List<Tutorial> findByTitleContainingIgnoreCase(String title);

List<Tutorial> findByTitleContainingOrDescriptionContaining(String title, String description);

List<Tutorial> findByTitleContainingIgnoreCaseAndPublished(String title, boolean isPublished);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Результат:

tutorials = tutorialRepository.findByTitleContainingIgnoreCase("dat");
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
*/

String text = "ot";
tutorials = tutorialRepository.findByTitleContainingOrDescriptionContaining(text, text);
show(tutorials);
/*
Tutorial [id=2, title=Java Spring Boot, description=Spring Framework Description, level=1, published=false, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=4, title=Spring Boot, description=Spring Boot Description, level=2, published=false, createdAt=2022-04-26 00:00:00.0]
*/

tutorials = tutorialRepository.findByTitleContainingAndPublished("ring", true);
// or
// tutorials = tutorialRepository.findByTitleContainingIgnoreCaseAndPublished("spring", true);
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=5, title=Spring JPA, description=Spring Data JPA Description, level=3, published=true, createdAt=2022-05-19 00:00:00.0]
Tutorial [id=6, title=Spring Batch, description=Spring Batch Description, level=4, published=true, createdAt=2022-05-19 00:00:00.0]
*/
Войти в полноэкранный режим

Выйти из полноэкранного режима

Поиск по нескольким полям с использованием JPQL

Давайте использовать @Query аннотация для создания Spring JPA Query с ключевыми словами SELECT и WHERE.

@Query("SELECT t FROM Tutorial t WHERE LOWER(t.title) LIKE LOWER(CONCAT('%', :keyword,'%')) OR LOWER(t.description) LIKE LOWER(CONCAT('%', :keyword,'%'))")
List<Tutorial> findByTitleContainingOrDescriptionContainingCaseInsensitive(String keyword);

@Query("SELECT t FROM Tutorial t WHERE LOWER(t.title) LIKE LOWER(CONCAT('%', :title,'%')) AND t.published=:isPublished")
List<Tutorial> findByTitleContainingCaseInsensitiveAndPublished(String title, boolean isPublished);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Результат:

tutorials = tutorialRepository.findByTitleContainingOrDescriptionContainingCaseInsensitive("data");
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=5, title=Spring JPA, description=Spring Data JPA Description, level=3, published=true, createdAt=2022-05-19 00:00:00.0]
*/

tutorials = tutorialRepository.findByTitleContainingCaseInsensitiveAndPublished("spring", true);
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=5, title=Spring JPA, description=Spring Data JPA Description, level=3, published=true, createdAt=2022-05-19 00:00:00.0]
Tutorial [id=6, title=Spring Batch, description=Spring Batch Description, level=4, published=true, createdAt=2022-05-19 00:00:00.0]
*/
Войти в полноэкранный режим

Выйти из полноэкранного режима

Поиск по нескольким полям с использованием собственного запроса

Мы также используем @Query аннотация для создания Spring JPA Native Query с ключевыми словами SELECT и WHERE.

@Query(value = "SELECT * FROM tutorials t WHERE LOWER(t.title) LIKE LOWER(CONCAT('%', :keyword,'%')) OR LOWER(t.description) LIKE LOWER(CONCAT('%', :keyword,'%'))", nativeQuery = true)
List<Tutorial> findByTitleContainingOrDescriptionContainingCaseInsensitive(String keyword);

@Query(value = "SELECT * FROM tutorials t WHERE LOWER(t.title) LIKE LOWER(CONCAT('%', :title,'%')) AND t.published=:isPublished", nativeQuery = true)
List<Tutorial> findByTitleContainingCaseInsensitiveAndPublished(String title, boolean isPublished);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Результат:

tutorials = tutorialRepository.findByTitleContainingOrDescriptionContainingCaseInsensitive("data");
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=5, title=Spring JPA, description=Spring Data JPA Description, level=3, published=true, createdAt=2022-05-19 00:00:00.0]
*/

tutorials = tutorialRepository.findByTitleContainingCaseInsensitiveAndPublished("spring", true);
show(tutorials);
/*
Tutorial [id=1, title=Spring Data, description=Spring Data Description, level=3, published=true, createdAt=2022-03-11 00:00:00.0]
Tutorial [id=5, title=Spring JPA, description=Spring Data JPA Description, level=3, published=true, createdAt=2022-05-19 00:00:00.0]
Tutorial [id=6, title=Spring Batch, description=Spring Batch Description, level=4, published=true, createdAt=2022-05-19 00:00:00.0]
*/
Войти в полноэкранный режим

Выйти из полноэкранного режима

Запустите проект JPA Filter по нескольким столбцам

Давайте откроем SpringJpaRepositoryQueryExampleApplication.javaбудем реализовывать CommandLineRunner и автопровод TutorialRepository Интерфейс для запуска методов JPA Query здесь.

package com.bezkoder.spring.jpa.query;

// import ...

@SpringBootApplication
public class SpringJpaRepositoryQueryExampleApplication implements CommandLineRunner {

  @Autowired
  TutorialRepository tutorialRepository;

  public static void main(String[] args) {
    SpringApplication.run(SpringJpaRepositoryQueryExampleApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    // call tutorialRepository methods here
  }

  private void show(List<Tutorial> tutorials) {
    tutorials.forEach(System.out::println);
  }
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Вывод

Сегодня мы узнали, как использовать репозиторий JPA для поиска/фильтрации по нескольким столбцам в примере Spring Boot с использованием Derived Query, JPQL и Native Query.
Мы можем запрашивать любое количество полей, разделенных логическими операторами (И, ИЛИ).

Вы можете продолжать писать CRUD Rest API с помощью:
Spring Boot, Spring Data JPA — пример Rest CRUD API

Если вы хотите написать модульный тест для репозитория JPA:
Модульный тест Spring Boot для репозитория JPA с @DataJpaTest

Вы также можете знать:

Приятного обучения! Увидимся.

Исходный код

Вы можете найти полный исходный код для этого руководства на Github, который использует:

Дальнейшее чтение

Полное приложение CRUD:

Ассоциации: