1. 概述

在本文中,我们将介绍在 Spring Data JPA 中构建 LIKE 查询的几种方式。

我们将从 Repository 中的查询方法关键字讲起,然后介绍如何使用 @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
}

然后插入一些测试数据:

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 查询方法

Spring Data JPA 提供了多种关键字来简化 LIKE 查询的构建,适用于大部分简单场景。

3.1. Containing、Contains、IsContaining 和 Like

如果我们想执行如下 SQL:

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

可以使用以下几种方法定义:

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

调用这些方法时,传入 "in" 即可:

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());

这三种方式行为一致,返回结果相同。

还有一个 Like 关键字,但需要我们手动添加通配符:

List<Movie> findByTitleLike(String title);

调用时必须带上 %

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

3.2. StartsWith

如果我们想查询评级以 PG 开头的所有电影:

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

可以使用 StartsWith

List<Movie> findByRatingStartsWith(String rating);

调用方式:

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

3.3. EndsWith

StartsWith 相反,EndsWith 用于模糊匹配字段结尾:

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

定义方法如下:

List<Movie> findByDirectorEndsWith(String director);

调用:

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

3.4. 忽略大小写

有时候我们需要忽略大小写匹配,例如查找包含 "the" 的电影名,无论大小写。

可以使用 IgnoreCase

List<Movie> findByTitleContainingIgnoreCase(String title);

调用:

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

3.5. Not 查询

有时候我们需要反向匹配,比如查找不包含某个关键词的记录。

可以使用如下关键字:

  • NotContains
  • NotContaining
  • NotLike

例如查找评级不包含 "PG" 的电影:

List<Movie> findByRatingNotContaining(String rating);

调用:

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

也可以用 NotLike 来实现类似 NOT LIKE 'An%' 的效果:

List<Movie> findByDirectorNotLike(String director);

调用:

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

4. 使用 @Query 注解

当查询逻辑复杂或方法名太长时,推荐使用 @Query 注解来自定义查询。

4.1. 命名参数

等价于 findByTitleContaining 方法:

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

使用时传入参数即可:

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

4.2. 顺序参数

也可以使用顺序参数:

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

调用:

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

⚠️ 对于外部传入的参数,建议进行转义,防止 SQL 注入(尤其在 LIKE 中使用 % 时)。

Spring Boot 2.4.1 及以上版本支持使用 SpEL 的 escape 方法:

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

调用:

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

5. 总结

本文我们学习了两种在 Spring JPA 中实现 LIKE 查询的方式:

✅ 使用 Repository 中的关键字方法(如 ContainingStartsWithEndsWithIgnoreCase 等)快速构建简单查询
✅ 使用 @Query 注解实现更灵活、复杂的查询逻辑,支持命名参数和顺序参数

两种方式各有适用场景,建议根据实际需求选择。对于简单模糊匹配,优先使用关键字方法;对于复杂查询或需精确控制通配符位置的场景,则推荐使用 @Query


原始标题:LIKE Queries in Spring JPA Repositories | Baeldung