repository jpa,spring data jpa in查询

  repository jpa,spring data jpa in查询

  00-1010 1.查询方法定义2详解。搜索查询策略3。查询创建4。属性表达式5。特殊参数处理。限制查询结果7。repository方法返回集合或Iterable S8。存储库方法处理Null9。查询结果流10。异步查询结果。

  

目录

存储库代理有两种方式从方法名中导出特定的存储查询。

 

  通过直接从方法名导出查询。通过使用手动定义的查询。可用选项取决于实际商店。但是,必须有一个策略来决定创建什么样的实际查询。

  00-1010存储库可以使用以下策略来解决基础架构查询。对于XML配置,可以通过query-lookup-strategy属性在名称空间中配置策略。对于Java配置,您可以使用Enable $ { store }存储库注释的queryLookupStrategy属性。某些策略可能不受特定数据存储的支持。

  创建;试图根据查询方法的名称构建特定于存储的查询。通常的做法是从方法名中删除一组已知的前缀,然后解析方法的其余部分。USE _ DECLARED _ QUERY尝试找到一个声明的查询,如果没有,抛出一个异常。查询可以通过注释来定义,也可以通过其他方式来声明。请参考特定存储的文档,以找到该存储的可用选项。如果版本库基础结构在启动时没有找到为此方法声明的查询,它将失败。CREATE_IF_NOT_FOUND(默认)组合CREATE和USE_DECLARED_QUERY。首先,它寻找一个声明的查询。如果没有找到声明的查询,它将根据方法名创建一个自定义查询。这是默认的查询策略。因此,如果您没有显式配置任何东西,将使用此策略。它允许您通过方法名快速定义查询,但是您也可以根据需要通过引入声明的查询来自定义这些查询。

  

1.查询方法定义详解

内置于Spring数据仓库的基本框架中,查询生成器机制对于在仓库的实体上构建约束查询非常有用。

 

  例1. 从方法名创建查询

  接口PersonRepository扩展RepositoryPerson,Long { list person findbyemailaddresandlastname(email address email address,String last name);//在查询中添加重复的关键字列表person findestintppeoplebylastnameorfirstname(字符串姓氏,字符串名字);list person findppeopledistincbylastnameorfirstname(字符串姓氏,字符串名字);//查询中的关键字忽略list person findbylastnamenorecase(字符串姓氏)的大小写;//对所有合适的属性list person findbylastname andfirstnameallignorecase(String last name,String firstname)启用忽略大小写;//查询使用静态排序规则list person findbyfirstnameordbyfirstnameasyc(string last name);list person findByLastnameOrderByFirstnameDesc(String last name);}解析查询方法的名称分为主语和谓语。

  第一部分(find…By,exists…By)定义了查询的主题,

  第二部分构成谓语。介绍句(主语)可以包含进一步的表达。

  find(或其他引入的关键字)和By之间的任何文本都被认为是描述性的,除非使用了限制结果的关键字,如Distinct以在要创建的查询上设置不同的标志,或Top/First以限制查询结果。

  附录包含查询方法主题关键字和查询方法谓词关键字的完整列表,包括排序和字母修饰符。但是,第一个By充当分隔符,指示实际条件谓词的开始。在非常基本的层面上,您可以在实体属性上定义条件,并用And和Or将它们连接起来。

  解析方法的实际结果取决于为其创建查询的持久性存储。但是,有一些一般的限制需要注意:

  表达式通常是属性遍历和可以连接的操作符的组合。您可以使用和。

  和OR来组合属性表达式。你还可以得到对运算符的支持,如属性表达式的Between、LessThan、GreaterThan和Like。支持的运算符可能因数据存储的不同而不同,所以请查阅参考文档的适当部分。方法解析器支持为单个属性(例如,findByLastnameIgnoreCase(…))或支持忽略大小写的类型的所有属性(通常是字符串实例–例如,findByLastnameAndFirstnameAllIgnoreCase(…))设置忽略大小写标志。是否支持忽略大小写可能因商店而异,所以请查阅参考文档中的相关章节,了解特定商店的查询方法。你可以通过在引用属性的查询方法中附加一个OrderBy子句,并提供一个排序方向(Asc或Desc)来应用静态排序。要创建一个支持动态排序的查询方法,请参阅 特殊参数处理。

 

  

4.属性表达式

属性表达式只能引用被管理实体的一个直接属性,如前面的例子所示。在查询创建时,你已经确保解析的属性是被管理的实体类的一个对应属性。然而,你也可以通过遍历嵌套属性来定义约束。考虑一下下面的方法签名。

 

  例2

  

List<Person> findByAddressZipCode(ZipCode zipCode);

假设一个人有一个带有ZipCode的地址。在这种情况下,该方法创建x.address.zipCode属性遍历。解析算法首先将整个部分(AddressZipCode)解释为属性,并检查实体类中是否有该名称的属性(未加首字母)。如果算法成功,它就使用该属性。如果没有,该算法将原始的骆驼字母部分从右侧分割成头和尾,并试图找到相应的属性–在我们的例子中,是AddressZip和Code。如果该算法找到了具有该头部的属性,它就取其尾部,并从那里继续向下构建树,以刚才描述的方式将尾部分割开来。如果第一次分割不匹配,该算法将分割点移到左边(Address, ZipCode),然后继续。

 

  虽然这在大多数情况下应该是有效的,但该算法有可能选择错误的属性。假设人的类也有一个addressZip属性。该算法将在第一轮分割中已经匹配,选择错误的属性,并且失败(因为addressZip的类型可能没有代码属性)。

  为了解决这种模糊性,你可以在你的方法名里面使用_来手动定义遍历点。所以我们的方法名将如下。

  例3

  

List<Person> findByAddress_ZipCode(ZipCode zipCode);

因为我们把下划线字符当作一个保留字符,所以我们强烈建议遵循标准的Java命名惯例(也就是说,不要在属性名中使用下划线,而是使用骆驼大写)。

 

  

 

  

5.特殊参数处理

为了处理你的查询中的参数,定义方法参数,正如在前面的例子中已经看到的。除此之外,基础设施还能识别某些特定的类型,如 Pageable和 Sort,以动态地将 分页和 排序应用于你的查询。下面的例子演示了这些功能。

 

  例4 在查询方法中使用分页、切割、排序

  

Page<User> findByLastname(String lastname, Pageable pageable);Slice<User> findByLastname(String lastname, Pageable pageable);List<User> findByLastname(String lastname, Sort sort);List<User> findByLastname(String lastname, Pageable pageable);

注意:采取Sort和Pageable的API希望将非空值交到方法中。如果你不想应用任何排序或分页,请使用Sort.unsorted()和Pageable.unpaged()方法。

 

  第一个方法让你把org.springframework.data.domain.Pageable实例传递给query方法,以动态地将分页添加到你静态定义的查询中。一个Page知道可用的元素和页面的总数。它是通过基础设施触发一个计数查询来计算总数量。

  由于这可能是昂贵的(取决于使用的存储),你可以改成返回一个Slice。一个Slice只知道下一个Slice是否可用,这在走过一个较大的结果集时可能就足够了。

  排序选项也是通过Pageable实例处理的。如果你只需要排序,可以在你的方法中添加一个org.springframework.data.domain.Sort参数。正如你所看到的,返回一个List也是可能的。在这种情况下,构建实际的Page实例所需的额外元数据并没有被创建(这反过来意味着不需要发出额外的计数查询)。相反,它限制了查询,只查询给定范围的实体。

  要想知道你在整个查询中得到多少页,你必须触发一个额外的计数查询。默认情况下,这个查询是由你实际触发的查询派生出来的。

  分页和排序

  我们可以通过使用属性名称来定义简单的排序表达式。你可以将表达式连接起来,将多个标准收集到一个表达式中。

  例5 定义排序表达式

  

Sort sort = Sort.by("firstname").ascending() .and(Sort.by("lastname").descending());

对于定义排序表达式的更加类型安全的方式,从定义排序表达式的类型开始,使用方法引用来定义排序的属性。

 

  例6 通过使用类型安全的API来定义排序表达式

  

TypedSort<Person> person = Sort.sort(Person.class);Sort sort = person.by(Person::getFirstname).ascending() .and(person.by(Person::getLastname).descending());

TypedSort.by(…)通过(通常)使用CGlib来使用运行时代理,这在使用Graal VM Native等工具时可能会干扰本地图像的编译。

 

  如果你的存储实现支持Querydsl,你也可以使用生成的元模型类型来定义排序表达式。

  例7 通过使用Querydsl API定义排序表达式

  

QSort sort = QSort.by(QPerson.firstname.asc()) .and(QSort.by(QPerson.lastname.desc()));

 

  

6.限制查询结果

你可以通过使用first或top关键字来限制查询方法的结果,这两个关键字可以互换使用。你可以在top或first后面附加一个可选的数值,以指定要返回的最大结果大小。如果不加数字,就会假定结果大小为1。下面的例子显示了如何限制查询的大小。

 

  例8. 用Top和First限制查询结果的大小

  

User findFirstByOrderByLastnameAsc();User findTopByOrderByAgeDesc();Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);Slice<User> findTop3ByLastname(String lastname, Pageable pageable);List<User> findFirst10ByLastname(String lastname, Sort sort);List<User> findTop10ByLastname(String lastname, Pageable pageable);

对于支持不同查询的数据集,限制表达式也支持Distinct关键字。另外,对于将结果集限制为一个实例的查询,支持用Optional关键字将结果包入。

 

  如果分页或切片应用于限制性查询的分页(以及可用页数的计算),则会在限制性结果内应用。

  通过使用排序参数将结果与动态排序相结合,可以让你表达对 "K "最小元素和 "K "最大元素的查询方法。

  

 

  

7. repository方法返回Collections or Iterables

当查询方法返回多个结果时,可以使用标准的Java Iterable、List和Set来接受返回结果。除此之外,我们还支持返回Spring Data的Streamable,这是Iterable的一个自定义扩展,以及Vavr提供的集合类型。请参考附录中对所有可能的查询方法返回类型的解释。

 

  例9 使用Streamable作为查询方法的返回类型

  

interface PersonRepository extends Repository<Person, Long> {Streamable`<Person>` findByFirstnameContaining(String firstname);Streamable`<Person>` findByLastnameContaining(String lastname);}Streamable `<Person>` result = repository.findByFirstnameContaining("av").and(repository.findByLastnameContaining("ea"));

例10 返回类型为自定义的Streamable包装类

 

  Streamable包装类是为集合类提供的一种特殊的封装类型, 是一种常用的模式,为返回多个元素的查询结果提供API。通常,这些类型是通过调用返回类似集合类型的repository方法,并手动创建包装器类型的实例来使用。你可以避免这个额外的步骤,因为Spring Data允许你使用这些包装器类型作为查询方法的返回类型,如果它们满足以下条件:

  该类型实现了Streamable。该类型暴露了一个构造函数或一个名为of(…)或valueOf(…)的静态工厂方法,它将Streamable作为参数。下面的列表显示了一个例子。

  

class Product { MonetaryAmount getPrice() { … }}@RequiredArgsConstructor(staticName = "of")class Products implements Streamable<Product> { private final Streamable<Product> streamable; public MonetaryAmount getTotal() { return streamable.stream() .map(Priced::getPrice) .reduce(Money.of(0), MonetaryAmount::add); } @Override public Iterator<Product> iterator() { return streamable.iterator(); }}interface ProductRepository implements Repository<Product, Long> { Products findAllByDescriptionContaining(String text); }

一个Product实体类对象暴露了访问产品价格的API。

 

  一个Streamable<Product>的封装类型,可以通过使用Products.of(…)(用Lombok注解创建的工厂方法)构建。使用Streamable<Product>的标准构造函数也可以做到。

  封装类型暴露了一个额外的API,计算Streamable<Product>上的新值。

  实现Streamable接口并委托给实际结果。

  那个包装类型的Products可以直接作为查询方法的返回类型使用。你不需要返回Streamable<Product>并在版本库客户端的查询后手动包装它。对于Vavr类型集合的支持

  Vavr是一个拥抱Java中函数式编程概念的库。它带有一组自定义的集合类型,你可以将其作为查询方法的返回类型,如下表所示。

  Vavr 集合类被使用的Vavr 实现类有效的Java源类型io.vavr.collection.Seqio.vavr.collection.Listjava.util.Iterableio.vavr.collection.Setio.vavr.collection.LinkedHashSetjava.util.Iterableio.vavr.collection.Mapio.vavr.collection.LinkedHashMapjava.util.Map你可以使用第一列中的类型(或其子类型)作为查询方法的返回类型,并根据实际查询结果的Java类型(第三列),获得第二列中的类型作为实现类型使用。

  或者,你可以声明Traversable(相当于Vavr Iterable),然后我们从实际返回值中派生出实现类。也就是说,java.util.List会变成Vavr List或Seq,java.util.Set会变成Vavr LinkedHashSet Set,以此类推。

  

 

  

8.repository方法处理Null

从Spring Data 2.0开始,返回单个聚合实例的存储库CRUD方法使用Java 8的Optional来处理空值。除此之外,Spring Data还支持在查询方法上返回以下封装类型。

 

  com.google.common.base.Optionalscala.Optionio.vavr.control.Option另外,查询方法可以选择完全不使用包装类型。没有查询结果会通过返回null来表示。Repository 方法返回集合、集合替代物、包装器和流,保证不会返回 null,而是返回相应的空表示。详见 Repository 查询返回类型。

  注解处理Null

  你可以通过使用Spring Framework的nullability注解来表达repository方法的nullability约束。它们提供了一种工具友好的方法,并在运行时选择加入空值检查,如下所示。

  @NonNullApi: 在包的层面上使用,声明参数和返回值的默认行为分别是不接受也不产生空值。@NonNull。用于不得为空的参数或返回值(在适用@NonNullApi的参数和返回值上不需要)。@Nullable。用在可以为空的参数或返回值上。Spring注解是用JSR 305注解(一个休眠但广泛使用的JSR)进行元注解的。JSR 305元注释让工具供应商(如IDEA、Eclipse和Kotlin)以通用的方式提供null-safety支持,而无需对Spring注释进行硬编码支持。为了在运行时检查查询方法的无效性约束,你需要通过在package-info.java中使用Spring的@NonNullApi,在包级别上激活无效性,如下例所示。

  例11 在 package-info.java中声明Non-nullability

  

@org.springframework.lang.NonNullApipackage com.acme;

一旦非空默认到位,repository的查询方法调用就会在运行时被验证是否有空值约束。如果查询结果违反了定义的约束,就会抛出一个异常。这种情况发生在方法会返回null,但被声明为non-nullable(在版本库所在的包上定义注解的默认值)。如果你想再次选择加入可归零的结果,可以有选择地在个别方法上使用@Nullable。使用本节开头提到的结果封装类型继续按预期工作:一个空的结果被翻译成代表不存在的值。

 

  下面的例子展示了刚才描述的一些技术。

  例12. 使用不同的无效性约束

  

package com.acme; import org.springframework.lang.Nullable;interface UserRepository extends Repository<User, Long> { User getByEmailAddress(EmailAddress emailAddress); @Nullable User findByEmailAddress(@Nullable EmailAddress emailAdress); Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress); }

repository驻留在一个包(或子包)中,我们为其定义了非空的行为。

 

  当查询没有产生结果时,抛出一个EmptyResultDataAccessException。

  当交给该方法的emailAddress为空时,抛出一个IllegalArgumentException。

  当查询没有产生结果时,返回null。也接受null作为emailAddress的值。

  当查询没有产生结果时返回Optional.empty()。当交给该方法的emailAddress为null时,抛出一个IllegalArgumentException。

  

 

  

9.查询结果流

你可以通过使用Java 8 Stream <T>作为返回类型来增量地处理查询方法的结果。如下面的例子所示,不把查询结果包裹在Stream中,而是使用数据存储的特定方法来执行流式处理。

 

  例13 用Java 8 Stream <T>串联查询的结果

  

@Query("select u from User u")Stream<User> findAllByCustomQueryAndStream();Stream<User> readAllByFirstnameNotNull();@Query("select u from User u")Stream<User> streamAllPaged(Pageable pageable);

一个流可能包裹了底层数据存储的特定资源,因此,在使用后必须关闭。你可以通过使用close()方法来手动关闭Stream,或者使用Java 7 try-with-resources块来关闭,如下面的例子中所示。

 

  例14 在 try-with-resources 块中处理一个 Stream <T> 的结果

  

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) { stream.forEach(…);}

目前并非所有的Spring Data模块都支持Stream <T>作为返回类型。

 

  

 

  

10.异步查询结果

你可以通过使用Spring的异步方法运行能力来异步运行repository查询。这意味着该方法在调用后立即返回,而实际的查询发生在一个已经提交给Spring TaskExecutor的任务中。异步查询与反应式查询不同,不应混合使用。关于响应式支持的更多细节,请参见store-specific文档。下面的例子显示了一些异步查询的情况。

 

  例15. 异步查询结果

  

@AsyncFuture<User> findByFirstname(String firstname); @AsyncCompletableFuture<User> findOneByFirstname(String firstname); @AsyncListenableFuture<User> findOneByLastname(String lastname);

使用java.util.concurrent.Future作为返回类型。

 

  使用Java 8 java.util.concurrent.CompletableFuture作为返回类型。

  使用org.springframework.util.concurrent.ListenableFuture作为返回类型。

  以上就是详解Spring Data JPA中Repository的接口查询方法的详细内容,更多关于Repository接口查询的资料请关注盛行IT其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: