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

Запросы LIKE в репозиториях Spring JPA

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

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

В этом кратком руководстве мы рассмотрим различные способы создания запросов LIKE в репозиториях Spring JPA .

Мы начнем с рассмотрения различных ключевых слов, которые мы можем использовать при создании методов запросов. Затем мы рассмотрим аннотацию @Query с именованными и упорядоченными параметрами.

2. Настройка

В нашем примере мы будем запрашивать таблицу фильмов .

Давайте определим нашу сущность Movie :

@Entity
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String title;
private String director;
private String rating;
private int duration;

// standard getters and setters
}

Определив сущность Movie , давайте создадим несколько примеров операторов вставки:

INSERT INTO movie(id, title, director, rating, duration) 
VALUES(1, 'Godzilla: King of the Monsters', ' Michael Dougherty', 'PG-13', 132);
INSERT INTO movie(id, title, director, rating, duration)
VALUES(2, 'Avengers: Endgame', 'Anthony Russo', 'PG-13', 181);
INSERT INTO movie(id, title, director, rating, duration)
VALUES(3, 'Captain Marvel', 'Anna Boden', 'PG-13', 123);
INSERT INTO movie(id, title, director, rating, duration)
VALUES(4, 'Dumbo', 'Tim Burton', 'PG', 112);
INSERT INTO movie(id, title, director, rating, duration)
VALUES(5, 'Booksmart', 'Olivia Wilde', 'R', 102);
INSERT INTO movie(id, title, director, rating, duration)
VALUES(6, 'Aladdin', 'Guy Ritchie', 'PG', 128);
INSERT INTO movie(id, title, director, rating, duration)
VALUES(7, 'The Sun Is Also a Star', 'Ry Russo-Young', 'PG-13', 100);

3. Нравятся методы запроса

Для многих простых сценариев запросов LIKE мы можем использовать различные ключевые слова для создания методов запросов в наших репозиториях.

Давайте исследуем их сейчас.

3.1. Содержит , Содержит , Содержит и Нравится

Давайте посмотрим, как мы можем выполнить следующий запрос LIKE с помощью метода запроса:

SELECT * FROM movie WHERE title LIKE '%in%';

Во-первых, давайте определим методы запроса, используя Containing , Contains и IsContaining :

List<Movie> findByTitleContaining(String title);
List<Movie> findByTitleContains(String title);
List<Movie> findByTitleIsContaining(String title);

Давайте вызовем наши методы запроса с частичным заголовком в :

List<Movie> results = movieRepository.findByTitleContaining("in");
assertEquals(3, results.size());

results = movieRepository.findByTitleIsContaining("in");
assertEquals(3, results.size());

results = movieRepository.findByTitleContains("in");
assertEquals(3, results.size());

Мы можем ожидать, что каждый из трех методов вернет одинаковые результаты.

Spring также предоставляет нам ключевое слово Like , но оно ведет себя немного по-другому, поскольку нам необходимо указать подстановочный знак с нашим параметром поиска.

Давайте определим метод запроса LIKE:

List<Movie> findByTitleLike(String title);

Теперь мы вызовем наш метод findByTitleLike с тем же значением, которое мы использовали ранее, но включая подстановочные знаки:

results = movieRepository.findByTitleLike("%in%");
assertEquals(3, results.size());

3.2. Начинается с

Давайте посмотрим на следующий запрос:

SELECT * FROM Movie WHERE Rating LIKE 'PG%';

Мы будем использовать ключевое слово StartsWith для создания метода запроса:

List<Movie> findByRatingStartsWith(String rating);

Определив наш метод, давайте вызовем его со значением PG :

List<Movie> results = movieRepository.findByRatingStartsWith("PG");
assertEquals(6, results.size());

3.3. заканчивается с

Spring предоставляет нам противоположную функциональность с помощью ключевого слова EndsWith .

Рассмотрим этот запрос:

SELECT * FROM Movie WHERE director LIKE '%Burton';

Теперь мы определим метод запроса EndsWith :

List<Movie> findByDirectorEndsWith(String director);

Как только мы определили наш метод, давайте вызовем его с параметром Burton :

List<Movie> results = movieRepository.findByDirectorEndsWith("Burton");
assertEquals(1, results.size());

3.4. Нечувствительность к регистру

Мы часто хотим найти все записи, содержащие определенную строку, независимо от регистра. В SQL мы могли бы добиться этого, заставив столбец использовать все заглавные или строчные буквы и предоставив то же самое со значениями, которые мы запрашиваем.

С Spring JPA мы можем использовать ключевое слово IgnoreCase в сочетании с одним из наших других ключевых слов :

List<Movie> findByTitleContainingIgnoreCase(String title);

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

List<Movie> results = movieRepository.findByTitleContainingIgnoreCase("the");
assertEquals(2, results.size());

3.5. Нет

Иногда нам нужно найти все записи, не содержащие определенную строку. Для этого мы можем использовать ключевые слова NotContains , NotContaining и NotLike .

Давайте определим запрос, используя NotContaining , чтобы найти фильмы с рейтингом, не содержащим PG :

List<Movie> findByRatingNotContaining(String rating);

Теперь давайте вызовем наш только что определенный метод:

List<Movie> results = movieRepository.findByRatingNotContaining("PG");
assertEquals(1, results.size());

Чтобы добиться функциональности, которая находит записи, в которых имя директора не начинается с определенной строки, мы будем использовать ключевое слово NotLike , чтобы сохранить контроль над размещением подстановочных знаков:

List<Movie> findByDirectorNotLike(String director);

Наконец, давайте вызовем метод для поиска всех фильмов, в которых имя режиссера начинается не с An :

List<Movie> results = movieRepository.findByDirectorNotLike("An%");
assertEquals(5, results.size());

Мы можем использовать NotLike аналогичным образом, чтобы выполнить Not в сочетании с функциональностью EndsWith .

4. Использование @Query

Иногда нам нужно создавать запросы, которые слишком сложны для методов запроса или приводят к абсурдно длинным именам методов. В этих случаях мы можем использовать аннотацию @Query для запроса нашей базы данных.

4.1. Именованные параметры

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

@Query("SELECT m FROM Movie m WHERE m.title LIKE %:title%")
List<Movie> searchByTitleLike(@Param("title") String title);

Мы включаем наши подстановочные знаки в запрос, который мы предоставляем. Здесь важна аннотация @Param , потому что мы используем именованный параметр.

4.2. Упорядоченные параметры

В дополнение к именованным параметрам мы можем использовать упорядоченные параметры в наших запросах:

@Query("SELECT m FROM Movie m WHERE m.rating LIKE ?1%")
List<Movie> searchByRatingStartsWith(String rating);

У нас есть контроль над подстановочными знаками, поэтому этот запрос эквивалентен методу запроса findByRatingStartsWith .

Найдем все фильмы с рейтингом, начинающимся с PG :

List<Movie> results = movieRepository.searchByRatingStartsWith("PG");
assertEquals(6, results.size());

Когда мы используем упорядоченные параметры в запросах LIKE с ненадежными данными, мы должны избегать входящих значений поиска.

Если мы используем Spring Boot 2.4.1 или более позднюю версию, мы можем использовать метод выхода SpEL : ``

@Query("SELECT m FROM Movie m WHERE m.director LIKE %?#{escape([0])} escape ?#{escapeCharacter()}")
List<Movie> searchByDirectorEndsWith(String director);

Теперь давайте вызовем наш метод со значением Burton :

List<Movie> results = movieRepository.searchByDirectorEndsWith("Burton");
assertEquals(1, results.size());

5. Вывод

В этой короткой статье мы узнали, как создавать запросы LIKE в репозиториях Spring JPA.

Во-первых, мы узнали, как использовать предоставленные ключевые слова для создания методов запроса.

Затем мы узнали, как выполнять те же задачи, используя параметр @Query как с именованными, так и с упорядоченными параметрами.

Полный код примера доступен на GitHub .