1、Spring Data JPA 中创建数据库查询方法的具体操作说明。方法中的SQL关键词和方法中的数据设置。
2、Spring Data JPA 中对属性字段的解析方式是什么样子的?属性表达式怎么介绍?
内部基础架构中有个根据方法名的查询生成器机制,对于在存储库的实体上构建约束查询很有用。
该机制方法的前缀有find…By、read…By、query…By、count…By和get…By,从这些方法可以分析它的其余部分(实体里面的字段)。
引入子句可以包含其他表达式,例如在Distinct要创建的查询上设置不同的标志。
然而,第一个By作为分隔符来指示实际标准的开始。在一个非常基本的水平上,你可以定义实体性条件,并与它们串联(And和Or)。
用一句话概括,待查询功能的方法名由查询策略(关键字)、查询字段和一些限制性条件组成。在如下例子中,可以直接在controller里面进行调用以查看效果:
interface PersonRepository extends Repository<User, Long> { // and的查询关系 List<User> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); //包含distinct去重、or的SQL语法 List<User> findDistinctPeopleByLastnameOrFirstname(Stringlastname, String firstname); List<User> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); //根据lastname字段查询忽略大小写 List<User> findByLastnamelgnoreCase(String lastname); //根据lastname和firstname查询equal并且忽略大小写 List<User> findByLastnameAndFirstnameAllIgnoreCase(Stringlastname, String firstname); //对查询结果根据lastname排序 List<User> findByLastnameOrderByFirstnameAsc(String lastname); List<User> findByLastnameOrderByFirstnameDesc(String lastname); }
解析方法的实际结果取决于创建查询的持久性存储。但是,有一些常见的事项需要注意:
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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 | findByAgeIsNull | … 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 age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
注意,除了find的前缀之外,我们查看PartTree的源码,还有如
下几种前缀:
private static final String QUERY_PATTERN = ” find | read | get | query | stream’; private static final String COUNT_PATTERN = "count"; private static final String EXISTS_PATTERN = "exists"; private static final String DELETE_PATTERN = "delete | remove';
使用的时候要配合不同的返回结果进行使用,例如:
interface UserRepository extends CrudRepository<User, Long> { long countByLastname (String lastname) ;//查询,总数 long deleteByLastname (String lastname) ; / / 根据一个字段进行删除操作 List<User> removeByLastname(String lastname); }
属性表达式(Property Expressions)只能引用托管(泛化)实体的直接属性,如前一个示例所示。
在查询创建时,你已经确保解析的属性是托管实体的属性。同时,还可以通过遍历嵌套属性定义约束。
假设一个Person实体对象里面有一个Address属性里面包含一个ZipCode属性。在这种情况下,方法名为:
List<Person> findByAddressZipCode(String zipCode);
创建及其查找的过程是:
虽然这在大多数情况下应该起作用,但是算法可能会选择错误的属性。假设Person类也有一个addressZip属性,该算法将在第一个分割轮中匹配,并且基本上会选择错误的属性,最后失败(因为该类型addressZip可能没有code属性)。
要解决这个歧义,可以在方法名称中手动定义遍历点,所以我们的方法名称最终会是:
List<Person> findByAddress_ZipCode(String zipCode);
当然Spring JPA里面是将下划线视为保留字符,但是强烈建议遵循标准Java命名约定(不使用属性名称中的下划线,而是使用骆驼示例)。命名属性的时候注意一下这个特性。
可以到PartTreeJpaQuery.class 查询相关的method的name 拆分和实现逻辑。