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 中的关键字方法(如 Containing
、StartsWith
、EndsWith
、IgnoreCase
等)快速构建简单查询
✅ 使用 @Query
注解实现更灵活、复杂的查询逻辑,支持命名参数和顺序参数
两种方式各有适用场景,建议根据实际需求选择。对于简单模糊匹配,优先使用关键字方法;对于复杂查询或需精确控制通配符位置的场景,则推荐使用 @Query
。