对于数据库的模糊查询,我们通常使用 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%")
前匹配与后匹配
使用startWith和endWith关键字能够完成前匹配与后匹配的效果,对应的 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 列表
| Keyword | Sample | JPQL snippet |
|---|---|---|
| Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
| And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
| Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
| Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
| Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
| LessThan | findByAgeLessThan | … where x.age < ?1 |
| LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
| GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
| GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
| After | findByStartDateAfter | … where x.startDate > ?1 |
| Before | findByStartDateBefore | … where x.startDate < ?1 |
| IsNull, Null | findByAge(Is)Null | … where x.age is null |
| IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age not null |
| Like | findByFirstnameLike | … where x.firstname like ?1 |
| NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
| StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
| EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
| Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
| OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
| Not | findByLastnameNot | … where x.lastname <> ?1 |
| In | findByAgeIn(Collection ages) | … where x.age in ?1 |
| NotIn | findByAgeNotIn(Collection ages) | … where x.age not in ?1 |
| True | findByActiveTrue() | … where x.active = true |
| False | findByActiveFalse() | … where x.active = false |
| IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |