如何使用 JPA 进行模糊查询

635 阅读2分钟

对于数据库的模糊查询,我们通常使用 like '%keyword%' 的方式编写 SQL 进行数据查询。

在 JPA 的语境下,如果不使用自定义手动编写 SQL 的方式,该如何实现 like关键字的查询呢?JPA 提供@Query注解支持开发人员能够自定义执行 SQL,同时也对 Query Methods 进行了一些约定,通过遵守这些约定就能满足绝大数简单的数据库操作

包含查询

对于 SQL

SELECT * FROM movie WHERE title like '%in%'

可以使用 Containing, Contains, IsContaining关键字定义查询方法

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

以上三种命名关键字的方式,都可以达到模糊匹配查询的效果

Spring 同样的也提供了LIKE关键字查询的实现,但是使用的时候需要我们拼接通配符,这点在体验上感觉很不舒服

//假设定义了一个 method
List<T> findByTitleLike(String title)

这个方法在实际使用过程中,如果想实现同样的模糊匹配的效果,则需要将通配符与参数值一起拼接才可以

List<T> lists=repository.findByTitleLike("%in%")

前匹配与后匹配

使用startWithendWith关键字能够完成前匹配与后匹配的效果,对应的 SQL 是

select * from movie where title like 'in%' -- startWith
select * from movie where title like '%in' -- endWith

对应的 JPA Repository 的方法命名为

List<T> findByTitleStartWith(String title);
List<T> findByTitleEndWith(String title);

分页模糊匹配

对于上述的几种匹配规则,如果想要在其基础上实现分页查询功能,JPA 也给我们提供了很简便的方式,只需要在参数中加入Pageable类型的参数即可

Page<T> findByTitleContains(String title,Pageable pageable);
Page<T> findByTitleContaining(String title,Pageable pageable);
Page<T> findByTitleLike(String title,Pageable pageable);
// .... 其他keywords命名的方法

目前 JPA 已支持的 keyword 列表

KeywordSampleJPQL snippet
DistinctfindDistinctByLastnameAndFirstnameselect distinct … where x.lastname = ?1 and x.firstname = ?2
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is, EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNull, NullfindByAge(Is)Null… where x.age is null
IsNotNull, NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstname) = UPPER(?1)