- 作者简介
- 内容提要
- 关于本书
- 路线图
- 代码规范与下载
- 作者在线
- 封面插图简介
- 前言
- 译者序
- 致谢
- 第1部分 Spring 的核心
- 第1章 Spring 之旅
- 第2章 装配 Bean
- 第3章 高级装配
- 第4章 面向切面的 Spring
- 第2部分 Web 中的 Spring
- 第5章 构建 Spring Web 应用程序
- 第6章 渲染 Web 视图
- 第7章 Spring MVC 的高级技术
- 第8章 使用 Spring Web Flow
- 第9章 保护 Web 应用
- 第3部分 后端中的 Spring
- 第10章 通过 Spring 和 JDBC 征服数据库
- 第11章 使用对象-关系映射持久化数据
- 第12章 使用 NoSQL 数据库
- 第13章 缓存数据
- 第14章 保护方法应用
- 第4部分 Spring 集成
- 第15章 使用远程服务
- 第16章 使用 Spring MVC 创建 REST API
- 第17章 Spring消息
- 第18章 使用 WebSocket 和 STOMP 实现消息功能
- 第19章 使用 Spring 发送 Email
- 第20章 使用 JMX 管理 Spring Bean
- 第21章 借助 Spring Boot 简化 Spring 开发
11.3.1 定义查询方法
现在,SpitterRepository需要完成的一项功能是根据给定的username查找Spitter对象。比如,我们将SpitterRepository接口修改为如下所示的样子:
这个新的findByUserName()非常简单,但是足以满足我们的需求。现在,该如何让Spring Data JPA提供这个方法的实现呢?
实际上,我们并不需要实现findByUsername()。方法签名已经告诉Spring Data JPA足够的信息来创建这个方法的实现了。
当创建Repository实现的时候,Spring Data会检查Repository接口的所有方法,解析方法的名称,并基于被持久化的对象来试图推测方法的目的。本质上,Spring Data定义了一组小型的领域特定语言(domain-specific language ,DSL),在这里,持久化的细节都是通过Repository方法的签名来描述的。
Spring Data能够知道这个方法是要查找Spitter的,因为我们使用Spitter对JpaRepository进行了参数化。方法名findByUsername确定该方法需要根据username属性相匹配来查找Spitter,而username是作为参数传递到方法中来的。另外,因为在方法签名中定义了该方法要返回一个Spitter对象,而不是一个集合,因此它只会查找一个username属性匹配的Spitter。
findByUsername()方法非常简单,但是Spring Data也能处理更加有意思的方法名称。Repository方法是由一个动词、一个可选的主题(Subject)、关键词By以及一个断言所组成。在findByUsername()这个样例中,动词是find,断言是Username,主题并没有指定,暗含的主题是Spitter。
作为编写Repository方法名称的样例,我们参照名为readSpitterByFirstname-OrLastname()的方法,看一下方法中的各个部分是如何映射的。图11.1展现了这个方法是如何拆分的。
我们可以看到,这里的动词是read,与之前样例中的find有所差别。Spring Data允许在方法名中使用四种动词:get、read、find和count。其中,动词get、read和find是同义的,这三个动词对应的Repository方法都会查询数据并返回对象。而动词count则会返回匹配对象的数量,而不是对象本身。
图11.1 Repository方法的命名遵循一种模式,有助于Spring Data
生成针对数据库的查询
Repository方法的主题是可选的。它的主要目的是让你在命名方法的时候,有更多的灵活性。如果你更愿意将方法称为readSpittersByFirstnameOrLastname()而不是 readByFirstnameOrLastname()的话,那么你尽可以这么做。
对于大部分场景来说,主题会被省略掉。readSpittersByFirstnameOrLastname()与readPuppiesByFirstnameOrLastname()并没有什么差别,它们与readThose ThingsWeWantByFirstnameOrLastname()同样没有什么区别。要查询的对象类型是通过如何参数化JpaRepository接口来确定的,而不是方法名称中的主题。
在省略主题的时候,有一种例外情况。如果主题的名称以Distinct开头的话,那么在生成查询的时候会确保所返回结果集中不包含重复记录。
断言是方法名称中最为有意思的部分,它指定了限制结果集的属性。在readByFirstnameOrLastname()这个样例中,会通过firstname属性或lastname属性的值来限制结果。
在断言中,会有一个或多个限制结果的条件。每个条件必须引用一个属性,并且还可以指定一种比较操作。如果省略比较操作符的话,那么这暗指是一种相等比较操作。不过,我们也可以选择其他的比较操作,包括如下的种类:
IsAfter、After、IsGreaterThan、GreaterThan
IsGreaterThanEqual、GreaterThanEqual
IsBefore、Before、IsLessThan、LessThan
IsLessThanEqual、LessThanEqual
IsBetween、Between
IsNull、Null
IsNotNull、NotNull
IsIn、In
IsNotIn、NotIn
IsStartingWith、StartingWith、StartsWith
IsEndingWith、EndingWith、EndsWith
IsContaining、Containing、Contains
IsLike、Like
IsNotLike、NotLike
IsTrue、True
IsFalse、False
Is、Equals
IsNot、Not
要对比的属性值就是方法的参数。完整的方法签名如下所示:
要处理String类型的属性时,条件中可能还会包含IgnoringCase或IgnoresCase,这样在执行对比的时候就会不再考虑字符是大写还是小写。例如,要在firstname和lastname属性上忽略大小写,那么可以将方法签名改成如下的形式:
需要注意,IgnoringCase和IgnoresCase是同义的,你可以随意挑选一个最合适的。
作为IgnoringCase/IgnoresCase的替代方案,我们还可以在所有条件的后面添加AllIgnoringCase或AllIgnoresCase,这样它就会忽略所有条件的大小写:
注意,参数的名称是无关紧要的,但是它们的顺序必须要与方法名称中的操作符相匹配。
最后,我们还可以在方法名称的结尾处添加OrderBy,实现结果集排序。例如,我们可以按照lastname属性升序排列结果集:
如果要根据多个属性排序的话,只需将其依序添加到OrderBy中即可。例如,下面的样例中,首先会根据lastname升序排列,然后根据firstname属性降序排列:
可以看到,条件部分是通过And或者Or进行分割的。
我们不可能(至少很难)提供一个权威的列表,将使用Spring Data方法命名约定可以编写出来的方法种类全部列出来。但是,如下给出了几个符合方法命名约定的方法签名:
List<Pet> findPetsByBreedIn(List<String> breed)
int countProductsByDiscontinuedTrue()
List<Order> findByShippingDateBetween(Date start, Date end)
我们只是初步体验了所能声明的方法种类,Spring Data JPA会为我们实现这些方法。现在,我们只需知道通过使用属性名和关键字构建Repository方法签名,就能让Spring Data JPA生成方法实现,完成几乎所有能够想象到的查询。
不过,Spring Data这个小型的DSL依旧有其局限性,有时候通过方法名称表达预期的查询很烦琐,甚至无法实现。如果遇到这种情形的话,Spring Data能够让我们通过@Query注解来解决问题。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论