详解Spring Data JPA中Repository的接口查询方法

目录
  • 1.查询方法定义详解
  • 2.搜索查询策略
  • 3.查询创建
  • 4.属性表达式
  • 5.特殊参数处理
  • 6.限制查询结果
  • 7. repository方法返回Collections or Iterables
  • 8.repository方法处理Null
  • 9.查询结果流
  • 10.异步查询结果

1.查询方法定义详解

repository代理有两种方式从方法名中派生出特定存储查询。

  • 通过直接从方法名派生查询。
  • 通过使用一个手动定义的查询。

可用的选项取决于实际的商店。然而,必须有一个策略来决定创建什么实际的查询。

2.搜索查询策略

下列策略可用于repository解决基础设施查询。对于 XML 配置,你可以通过 query-lookup-strategy 属性在命名空间配置该策略。对于 Java 配置,你可以使用 Enable${store}Repositories 注解的 queryLookupStrategy属性。某些策略可能不被特定的数据存储所支持。

  • CREATE; 试图从查询方法的名称中构建一个特定于存储的查询。一般的做法是,从方法名中删除一组已知的前缀,然后解析方法的其余部分。
  • USE_DECLARED_QUERY; 试图找到一个已声明的查询,如果找不到则抛出一个异常。查询可以由某个注解来定义,也可以通过其他方式来声明。请参阅特定存储的文档以找到该存储的可用选项。如果版本库基础设施在启动时没有为该方法找到一个已声明的查询,则会失败。
  • CREATE_IF_NOT_FOUND;(默认)结合了 CREATE 和 USE_DECLARED_QUERY。它首先查找一个已声明的查询,如果没有找到已声明的查询,它将创建一个基于方法名的自定义查询。这是默认的查询策略,因此,如果你没有明确地配置任何东西,就会使用这种策略。它允许通过方法名快速定义查询,但也可以根据需要通过引入已声明的查询对这些查询进行自定义调整。

3.查询创建

内置在Spring Data repository基础框架中,查询生成器机制对于在repository的实体上建立约束性查询非常有用。

例1. 从方法名创建查询

interface PersonRepository extends Repository<Person, Long> {
  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // 查询中添加去重关键字
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  // 查询中关键字忽略大小写
  List<Person> findByLastnameIgnoreCase(String lastname);

  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // 查询使用使用静态排序规则
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

解析查询方法名称分为 主语和 谓语。

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

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

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

附录中包含了查询方法主语关键词和查询方法谓语关键词的完整列表,包括排序和字母修饰语。然而,第一个By作为分界符,表示实际条件谓词的开始。在一个非常基本的层面上,你可以在实体属性上定义条件,并用And和Or来连接它们。

解析方法的实际结果取决于你为之创建查询的持久性存储。然而,有一些一般性约束需要注意:

  • 表达式通常是属性遍历与可以串联的运算符的结合。你可以用AND和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.Seq io.vavr.collection.List java.util.Iterable
io.vavr.collection.Set io.vavr.collection.LinkedHashSet java.util.Iterable
io.vavr.collection.Map io.vavr.collection.LinkedHashMap java.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.Optional
  • scala.Option
  • io.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.NonNullApi
package 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. 异步查询结果

@Async
Future<User> findByFirstname(String firstname);         

@Async
CompletableFuture<User> findOneByFirstname(String firstname); 

@Async
ListenableFuture<User> findOneByLastname(String lastname);

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

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

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

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

(0)

相关推荐

  • SpringData Repository接口用法解析

    本节主要介绍Repository接口规范,及其子接口 Repository是一个空接口,即标准接口若我们定义的接口继承了Repository,则该接口会被IOC容器识别为一个Repositoty Bean纳入到IOC容器中.进而可以在该接口中定义满足一定规范的方法.实际上也可以通过注解的方式定义Repository接口 package com.ntjr.springdata; import org.springframework.data.repository.RepositoryDefinit

  • JPA中JpaRepository接口的使用方式

    目录 JPA JpaRepository接口的使用 SpringData的所有接口 jpa Repository继承自定义接口的主意事项 整体代码如下 解决方案 JPA JpaRepository接口的使用 SpringData的所有接口 CrudRepository接口 ,其中提供了这些方法提供使用,同时继承了其父接口的方法 其中saveAndFlush()方法就相当于hibernate中的saveOrUpdate()和JPA中的merge() @Test public void JpaRep

  • Spring Data JPA框架快速入门之数据持久化存储到数据库

    目录 1 核心概念 CrudRepository接口 PagingAndSortingRepository接口 2 查询方法 3 后续内容介绍 1 核心概念 Spring Data存储库抽象的中心接口是Repository.它把要管理的实体类以及实体类的ID类型作为类型参数.这个接口主要是作为一个标记接口,用来捕捉工作中的类型,并帮助你发现扩展这个接口的接口.CrudRepository接口为被管理的实体类提供复杂的CRUD功能. 自己可以看看Repository的扩展接口以及实现类 IDEA中

  • Spring Data JPA框架快速入门之自定义Repository接口

    目录 自定义Repository接口 repository接口定义 使用Repository接口 自定义Repository接口 要定义一个repository接口,你首先需要自定义一个实体类专用的Repository接口.该接口必须扩展 Repository,并将其类型指定为实体类和实体类的 ID 类型. 如果你想为该实体类资源类型开放CRUD方法,请直接继承CrudRepository而不是Repository. repository接口定义 通常,你的repository接口会扩展Repo

  • 详解Spring Data JPA中Repository的接口查询方法

    目录 1.查询方法定义详解 2.搜索查询策略 3.查询创建 4.属性表达式 5.特殊参数处理 6.限制查询结果 7. repository方法返回Collections or Iterables 8.repository方法处理Null 9.查询结果流 10.异步查询结果 1.查询方法定义详解 repository代理有两种方式从方法名中派生出特定存储查询. 通过直接从方法名派生查询. 通过使用一个手动定义的查询. 可用的选项取决于实际的商店.然而,必须有一个策略来决定创建什么实际的查询. 2.

  • 详解Spring Data Jpa 模糊查询的正确用法

    模糊查询 Spring Data Jpa的使用可以减少开发者对sql语句的编写,甚至完全不需要编写sql语句.但是,开发过程中总会遇到各种复杂的场景以及大大小小的坑. 今天项目中某个功能模块需要用到模糊查询.原生sql中模糊查询关键字'Like',而Spring Data Jpa的Repository接口中恰恰也有实体字段对应的Like.但是,如果直接使用它,那么恭喜你,你幸运地掉坑了. Spring Data Jpa 模糊查询正确用法 首先,我们先创建一个实体用来存储我们的数据 /** * 实

  • 详解Spring Data JPA系列之投影(Projection)的用法

    本文介绍了Spring Data JPA系列之投影(Projection)的用法,分享给大家 在JPA的查询中,有一个不方便的地方,@Query注解,如果查询直接是 Select C from Customer c ,这时候,查询的返回对象就是Customer这个完整的对象,包含所有字段,对于我们的示例并没有什么问题,但是对于比较庞大的domain类,这个查询时就比较要命,并不是所有的字段都能用到,比较头疼.另外,如果定义 select c.firstName as firstName,c.la

  • 详解Spring Data Jpa当属性为Null也更新的完美解决方案

    开场白 我本来是一名android开发者,突然就对java后端产生了浓烈的兴趣.所以,立马就转到了后端.第一个项目使用的使用Spring Data Jpa来操作数据库的,可是在更新数据的时候发现一个问题,属性值为Null竟然也更新,这就会导致本来没有更新的属性值,全部就成了Null. 原因 经过一番度娘操作,原来Jpa,不知道你是想把属性设置为Null,还是不想. 解决方法 找到一个方法,就是在数据模型上加上注解@DynamicUpdate,可是发现并不好使.而后经过整理,找到以下解决方案 我们

  • 详解Spring Data JPA动态条件查询的写法

    我们在使用SpringData JPA框架时,进行条件查询,如果是固定条件的查询,我们可以使用符合框架规则的自定义方法以及@Query注解实现. 如果是查询条件是动态的,框架也提供了查询接口. JpaSpecificationExecutor 和其他接口使用方式一样,只需要在你的Dao接口继承即可(官网代码). public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecification

  • 详解Spring Data JPA使用@Query注解(Using @Query)

    经过几天的折腾,终于到了学习一个重量级的查询方式上,使用@Query注解,使用注解有两种方式,一种是JPQL的SQL语言方式,一种是原生SQL的语言,略有区别,后者我们更熟悉一些.话不多说,看代码. 1.在CustomerRepository里添加 /** * 模糊匹配 * @param bauer * @return */ @Query("select c from Customer c where c.firstName=?1") Customer findByFirstName2

  • 详解spring boot jpa整合QueryDSL来简化复杂操作

    前言 使用过spring data jpa的同学,都很清楚,对于复杂的sql查询,处理起来还是比较复杂的,而本文中的QueryDSL就是用来简化JPA操作的. Querydsl定义了一种常用的静态类型语法,用于在持久域模型数据之上进行查询.JDO和JPA是Querydsl的主要集成技术.本文旨在介绍如何使用Querydsl与JPA组合使用.JPA的Querydsl是JPQL和Criteria查询的替代方法.QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查

  • 详解Spring data 定义默认时间与日期的实例

    详解Spring data 定义默认时间与日期的实例 前言: 需求是这样的: 1. 创建时间与更新时间只能由数据库产生,不允许在实体类中产生,因为每个节点的时间/时区不一定一直.另外防止人为插入自定义时间时间. 2. 插入记录的时候创建默认时间,创建时间不能为空,时间一旦插入不允许日后在实体类中修改. 3. 记录创建后更新日志字段为默认为 null 表示该记录没有被修改过.一旦数据被修改,修改日期字段将记录下最后的修改时间. 4. 甚至你可以通过触发器实现一个history 表,用来记录数据的历

  • 在Spring Data JPA中引入Querydsl的实现方式

    一.环境说明 基础框架采用Spring Boot.Spring Data JPA.Hibernate.在动态查询中,有一种方式是采用Querydsl的方式. 二.具体配置 1.在pom.xml中,引入相关包和配置插件. (1)引入包(注:不需要版本号,Spring Boot 会自动匹配合适的版本) <!-- Querydsl相关包 --> <dependency> <groupId>com.querydsl</groupId> <artifactId&

  • Spring DATA JPA 中findAll 进行OrderBy方式

    目录 Spring DATA JPA 中findAll 进行OrderBy Spring Data JPA使用orderby的一个小坑 Spring DATA JPA 中findAll 进行OrderBy 需要在 repository 中 定义这样的方法 :findAllByOrderByUpdatedAtDesc() public List findAllByOrderByUpdatedAtDesc(); 重要:(中间要多加一个By) findAllByOrderByUpdatedAtDesc

随机推荐