Spring Data Jpa (三)定义查询方法

本章详细讲解如何利用方法名定义查询方法(Defining Query Methods)算法

(1)定义查询方法的配置方法spring

  因为Spring JPA Repository的实现原理是采用动态代理的机制,因此咱们介绍两种定义查询方法:从方法名称中能够指定特定用于存储的查询和更新,或经过使用@Query手动定义的查询,这个取决于实际存储操做。只须要实体Repository继承Spring Data Common里面的Repository接口便可,就像前面咱们讲的同样。若是你想有其余更多默认通用方法的实现,能够选择JpaRepository、PagingAndSortingRepository、CrudRepository等接口,也能够直接继承咱们后面要讲的JpaSpecificationExecutor、QueryByExampleExecutor和自定义Response,均可以达到一样的效果。api

  若是你不想扩展Spring数据接口,还可使用它来注解存储库接口@RepositoryDefinition。扩展CrudRepository公开了一套完整的方法来操纵实体。若是你但愿对所暴露的方法有选择性,只须要将暴露的方法复制CrudRepository到域库中便可。其实也是自定义Repository的一种。架构

  看下面的示例,选择性地暴露CRUD方法:框架

  在这个示例的第一步中为全部域存储库定义了一个公共基础接口,并将其暴露出来。findOne(…)和save(…)方法将被路由到由Spring Data提供的、你选择的存储库的基本存储库实现中,例如JPA中的SimpleJpaRepository。由于它们正在匹配方法签名CrudRepository,因此UserRepository将可以保存用户,并经过id查找单个用户信息,以及触发查询以经过其电子邮件地址查找Users。dom

 

(2)方法的查询策略设置异步

  经过@EnableJpaRepositories(queryLookupStrategy=QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND)能够配置方法的查询策略,其中QueryLookupStrategy.Key的值一共有三个。3d

  CREATE:直接根据方法名进行建立。规则是根据方法名称的构造进行尝试,通常的方法是从方法名中删除给定的一组已知前缀,并解析该方法的其他部分。若是方法名不符合规则,启动的时候就会报异常。代理

  USE_DECLARED_QUERY:声明方式建立,即本书说的注解方式。启动的时候会尝试找到一个声明的查询,若是没有找到就将抛出一个异常。查询能够由某处注释或其余方法声明。code

  CREATE_IF_NOT_FOUND:这个是默认的,以上两种方式的结合版。先用声明方式进行查找,若是没有找到与方法相匹配的查询,就用create的方法名建立规则建立一个查询。

 除非有特殊需求,通常直接用默认的,不用管。配置示例以下

  

(3)查询方法的建立

  内部基础架构中有个根据方法名的查询生成器机制,对于在存储库的实体上构建约束查询颇有用。该机制方法的前缀有find…By、read…By、query…By、count…By和get…By,从这些方法能够分析它的其他部分(实体里面的字段)。引入子句能够包含其余表达式,例如在Distinct要建立的查询上设置不一样的标志。然而,第一个By做为分隔符来指示实际标准的开始。在一个很是基本的水平上,你能够定义实体性条件,并与它们串联(And和Or)。

  用一句话归纳,待查询功能的方法名由查询策略(关键字)、查询字段和一些限制性条件组成。在以下例子中,能够直接在controller里面进行调用以查看效果:

  

  解析方法的实际结果取决于建立查询的持久性存储。可是,有一些常见的事项须要注意:

    表达式一般是能够链接的运算符的属性遍历。你可使用组合属性表达式AND和OR。你还能够将运算关键字Between、LessThan、GreaterThan、Like做为属性表达式。受支持的操做员可能因数据存储而异,所以请参阅官方参考文档的相应部份内容。

    该方法解析器支持设置一个IgnoreCase标志个别特性(例如,findByLastnameIgnoreCase(…))或支持忽略大小写(一般是一个类型的全部属性为String的状况下,例如,findByLastnameAndFirstnameAllIgnoreCase(…))。是否支持忽略示例可能会因存储而异,所以请参阅参考文档中的相关章节,了解特定于场景的查询方法。

   能够经过OrderBy在引用属性和提供排序方向(Asc或Desc)的查询方法中附加一个子句来应用静态排序。要建立支持动态排序的查询方法来影响查询结果。

 

(4)关键字列表

   

 

 

 

 

 

 

 

 

 

 

 

注意,除了find的前缀以外,咱们查看PartTree的源码,还有如
下几种前缀:

  

使用的时候要配合不一样的返回结果进行使用,例如:

  

 

(5)方法的查询策略的属性表达式

   属性表达式(Property Expressions)只能引用托管(泛化)实体的直接属性,如前一个示例所示。在查询建立时,你已经确保解析的属性是托管实体的属性。同时,还能够经过遍历嵌套属性定义约束。假设一个Person实体对象里面有一个Address属性里面包含一个ZipCode属性。在这种状况下,方法名为:

  建立及其查找的过程是:解析算法首先将整个part(AddressZipCode)解释为属性,并使用该名称(uncapitalized)检查域类的属性。若是算法成功,就使用该属性。若是不是,就拆分右侧驼峰部分的信号源到头部和尾部,并试图找出相应的属性,在咱们的例子中是AddressZip和Code。若是算法找到一个具备头部的属性,那么它须要尾部,并从那里继续构建树,然后按照刚刚描述的方式将尾部分割。若是第一个分割不匹配,就将分割点移动到左边(Address、ZipCode),而后继续。

  虽然这在大多数状况下应该起做用,可是算法可能会选择错误的属性。假设Person类也有一个addressZip属性,该算法将在第一个分割轮中匹配,而且基本上会选择错误的属性,最后失败(由于该类型addressZip可能没有code属性)。

  要解决这个歧义,能够在方法名称中手动定义遍历点,因此咱们的方法名称最终会是:

  固然Spring JPA里面是将下划线视为保留字符,可是强烈建议遵循标准Java命名约定(不使用属性名称中的下划线,而是使用骆驼示

例)。命名属性的时候注意一下这个特性。

  

(6)查询结果的处理

  1.参数选择分页和排序(Pageable/Sort)

    1.特定类型的参数,动态地将分页和排序应用于查询

    示例:在查询方法中使用Pageable、Slice和Sort。

    

    第一种方法容许将org.springframework.data.domain.Pageable实例传递给查询方法,以便动态地将分页添加到静态定义的查询中。Page知道可用的元素和页面的总数。它经过基础框架里面触发计数查询来计算总数。因为这多是昂贵的,具体取决于所使用的场景,说白了,当用到Pageable的时候会默认执行一条cout语句。而Slice的做用是,只知道是否有下一个Slice可用,不会执行count,因此当查询较大的结果集时,只知道数据是足够的就能够了,并且相关的业务场景也不用关心一共有多少页。

    排序选项也经过Pageable实例处理。若是只须要排序,那么在org.springframework.data.domain.Sort参数中添加一个参数便可。正如你能够看到的,只返回一个List也是可能的。在这种状况下,Page将不会建立构建实际实例所需的附加元数据(这反过来意味着必须不被发布的附加计数查询),而仅仅是限制查询仅查找给定范围的实体。

    2.限制查询结果

    示例:在查询方法上加限制查询结果的关键字first和top。

    

    查询方法的结果能够经过关键字来限制first或top,其能够被互换地使用。可选的数值能够追加到顶部/第一个以指定要返回的最大结果大小。若是数字被省略,则假设结果大小为1。限制表达式也支持Distinct关键字。此外,对于将结果集限制为一个实例的查询,支持将结果包装到一个实例中的Optional中。若是将分页或切片应用于限制查询分页(以及可用页数的计算),则在限制结果中应用。

  

  2.查询结果的不一样形式(List/Stream/Page/Future)

    Page和List在上面的示例中都有涉及,下面介绍几种特殊的。

    1.流式查询结果

      能够经过使用Java 8 Stream<T>做为返回类型来逐步处理查询方法的结果,而不是简单地将查询结果包装在Stream数据存储中,特定的方法用于执行流。

    

    

    2.异步查询结果

      可使用Spring的异步方法执行功能异步的存储库查询。这意味着方法将在调用时当即返回,而且实际的查询执行将发生在已提交给Spring TaskExecutor的任务中,比较适合定时任务的实际场景。

    

 3 Projections对查询结果的扩展

    Spring JPA对Projections扩展的支持是很是好的。从字面意思上理解就是映射,指的是和DB查询结果的字段映射关系。通常状况下,返回的字段和DB查询结果的字段是一一对应的,但有的时候,我们须要返回一些指定的字段,不须要所有返回,或者只返回一些复合型的字段,还要本身写逻辑。Spring Data正是考虑到了这一点,允许对专用返回类型进行建模,以便咱们有更多的选择,将部分字段显示成视图对象。

  假设Person是一个正常的实体,和数据表Person一一对应,正常的写法以下:

  

  (1)咱们想仅仅返回其中与name相关的字段,应该怎么作呢?基于projections的思路,实际上是比较容易的。咱们只须要声明一个

接口,包含要返回的属性的方法便可,例如:

  

  Repository里面的写法以下,直接用这个对象接收结果便可

 

  在Controtroller里面直接调用对象能够查看结果。原理是运行时底层会有动态代理机制为这个接口生成一个实现实体类。

  (2)查询关联的子对象,例如:

   

  (3)@Value和SPEL也支持:

    

    PersonRepository里面保持不变,这样会返回一个firstname和lastname相加的只有fullName的结果集合。

相关文章
相关标签/搜索