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 .