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 {
// and的查询关系
List findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
//包含distinct去重、or的SQL语法
List findDistinctPeopleByLastnameOrFirstname(Stringlastname, String firstname);
List findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
//根据lastname字段查询忽略大小写
List findByLastnamelgnoreCase(String lastname);
//根据lastname和firstname查询equal并且忽略大小写
List findByLastnameAndFirstnameAllIgnoreCase(Stringlastname, String firstname);
//对查询结果根据lastname排序
List findByLastnameOrderByFirstnameAsc(String lastname);
List findByLastnameOrderByFirstnameDesc(String lastname);
}
解析方法的实际结果取决于创建查询的持久性存储。但是,有一些常见的事项需要注意:
表达式通常是可以连接的运算符的属性遍历。你可以使用组合属性表达式AND和OR。你还可以将运算关键字Between、LessThan、GreaterThan、Like作为属性表达式。受支持的操作员可能因数据存储而异,因此请参阅官方参考文档的相应部分内容。
该方法解析器支持设置一个IgnoreCase标志个别特性(例如,findByLastnameIgnoreCase(…))或支持忽略大小写(通常是一个类型的所有属性为String的情况下,例如,findByLastnameAndFirstnameAllIgnoreCase(…))。是否支持忽略示例可能会因存储而异,因此请参阅参考文档中的相关章节,了解特定于场景的查询方法。
可以通过OrderBy在引用属性和提供排序方向(Asc或Desc)的查询方法中附加一个子句来应用静态排序。要创建支持动态排序的查询方法来影响查询结果。
四、关键字列表
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 {
long countByLastname (String lastname) ;//查询,总数
long deleteByLastname (String lastname) ; / / 根据一个字段进行删除操作
List removeByLastname(String lastname);
}
五、方法的查询策略的属性表达式
属性表达式(Property Expressions)只能引用托管(泛化)实体的直接属性,如前一个示例所示。
在查询创建时,你已经确保解析的属性是托管实体的属性。同时,还可以通过遍历嵌套属性定义约束。
假设一个Person实体对象里面有一个Address属性里面包含一个ZipCode属性。在这种情况下,方法名为:
List findByAddressZipCode(String zipCode);
创建及其查找的过程是:
解析算法首先将整个part(AddressZipCode)解释为属性,并使用该名称(uncapitalized)检查域类的属性。
如果算法成功,就使用该属性。
如果不是,就拆分右侧驼峰部分的信号源到头部和尾部,并试图找出相应的属性,在我们的例子中是AddressZip和Code。
如果算法找到一个具有头部的属性,那么它需要尾部,并从那里继续构建树,然后按照刚刚描述的方式将尾部分割。
如果第一个分割不匹配,就将分割点移动到左边(Address、ZipCode),然后继续。
虽然这在大多数情况下应该起作用,但是算法可能会选择错误的属性。假设Person类也有一个addressZip属性,该算法将在第一个分割轮中匹配,并且基本上会选择错误的属性,最后失败(因为该类型addressZip可能没有code属性)。
要解决这个歧义,可以在方法名称中手动定义遍历点,所以我们的方法名称最终会是:
List findByAddress_ZipCode(String zipCode);
当然Spring JPA里面是将下划线视为保留字符,但是强烈建议遵循标准Java命名约定(不使用属性名称中的下划线,而是使用骆驼示例)。命名属性的时候注意一下这个特性。
可以到PartTreeJpaQuery.class 查询相关的method的name 拆分和实现逻辑。