关于前端:Spring-Data-JPA-参考文档二

4次阅读

共计 10189 个字符,预计需要花费 26 分钟才能阅读完成。

原题目:Spring 认证 |Spring Data JPA 参考文档二(内容起源:Spring 中国教育管理中心)

Spring Data JPA 参考文档二
4.4.6. 返回汇合或可迭代对象的存储库办法
查询方法,返回多个后果能够应用规范的 Java Iterable,List 和 Set。除此之外,咱们反对返回 Spring Data 的 Streamable、的自定义扩大 Iterable 以及 Vavr 提供的汇合类型。请参阅解释所有可能的查询方法返回类型的附录。

应用 Streamable 作为查询方法返回类型
您能够应用任何汇合类型的 Streamable 代替 Iterable 品。它提供了拜访非并行 Stream(短少 from Iterable)的便捷办法,以及间接….filter(…)和….map(…)笼罩元素并将其连贯 Streamable 到其余元素的能力:

示例 19. 应用 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”));
返回自定义流包装器类型
为汇合提供专用包装器类型是一种罕用模式,用于为返回多个元素的查问后果提供 API。通常,通过调用存储库办法返回类汇合类型并手动创立包装器类型的实例来应用这些类型。您能够防止额定的步骤,因为 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);
}
Spring Data JPA 参考文档二
一个 Product 裸露的 API 来拜访产品的价格实体。

Streamable<Product> 能够通过应用 Products.of(…)(应用 Lombok 正文创立的工厂办法)结构的的包装器类型。采纳 Streamable<Product>will 的规范构造函数也能够。

包装器类型公开了一个额定的 API,在 Streamable<Product>.

实现 Streamable 接口并委托给理论后果。

该包装器类型 Products 能够间接用作查询方法返回类型。您不须要 Streamable<Product> 在存储库客户端中的查问之后返回并手动包装它。

反对 Vavr 汇合
Vavr 是一个蕴含 Java 函数式编程概念的库。它附带一组自定义汇合类型,您能够将其用作查询方法返回类型,如下表所示:

Spring Data JPA 参考文档二
您能够应用第一列(或其子类型)中的类型作为查询方法返回类型,并依据理论查问后果(第三列)的 Java 类型获取第二列中的类型作为实现类型。或者,您能够申明 Traversable(Iterable 相当于 Vavr),而后咱们从理论返回值派生实现类。也就是说,ajava.util.List 变成了 VavrList 或 Seq,ajava.util.Set 变成了 Vavr LinkedHashSet Set,依此类推。

4.4.7. 存储库办法的空解决
从 Spring Data 2.0 开始,返回单个聚合实例的存储库 CRUD 办法应用 Java 8Optional 来批示可能短少值。除此之外,Spring Data 反对在查询方法上返回以下包装器类型:

com.google.common.base.Optional
scala.Option
io.vavr.control.Option
或者,查询方法能够抉择基本不应用包装器类型。而后通过返回来批示不存在查问后果 null。返回汇合、汇合代替、包装器和流的存储库办法保障永远不会返回 null,而是返回相应的空示意。无关详细信息,请参阅“存储库查问返回类型”。

可空性正文
您能够应用 Spring Framework 的可空性正文来表白存储库办法的可空性束缚。它们 null 在运行时提供了一种工具敌对的办法和抉择退出查看,如下所示:

@NonNullApi: 在包级别上用于申明参数和返回值的默认行为别离是既不承受也不产生 null 值。
@NonNull: 用于不得为的参数或返回值 null(在 @NonNullApi 实用的参数和返回值上不须要)。
@Nullable: 用于能够是的参数或返回值 null。
Spring 正文应用 JSR 305 正文(一种休眠但宽泛应用的 JSR)进行元正文。JSR 305 元正文让工具供应商(例如 IDEA、Eclipse 和 Kotlin)以通用形式提供空平安反对,而无需对 Spring 正文进行硬编码反对。要为查询方法启用可空性束缚的运行时查看,您须要应用 Spring 的 @NonNullApiin 在包级别激活非可空性 package-info.java,如以下示例所示:

示例 20. 在 package-info.java

@org.springframework.lang.NonNullApi
package com.acme;
一旦非空默认设置到位,存储库查询方法调用将在运行时验证为可空性束缚。如果查问后果违反了定义的束缚,则抛出异样。当该办法将返回 null 但被申明为不可为空时(在存储库所在的包上定义的默认正文),就会产生这种状况。如果您想再次抉择可空后果,请有选择地应用 @Nullable 单个办法。应用本节结尾提到的后果包装器类型持续按预期工作:空后果被转换为示意不存在的值。

以下示例显示了刚刚形容的许多技术:

示例 21. 应用不同的可空性束缚

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);
}
Spring Data JPA 参考文档二
存储库驻留在咱们定义了非空行为的包(或子包)中。

EmptyResultDataAccessException 当查问未产生后果时抛出。IllegalArgumentException 当 emailAddress 传递给办法是时抛出 null。

null 当查问未产生后果时返回。也承受 null 作为的值 emailAddress。

Optional.empty()当查问未产生后果时返回。IllegalArgumentException 当 emailAddress 传递给办法是时抛出 null。

基于 Kotlin 的存储库中的可空性
Kotlin 在语言中定义了可空性束缚。Kotlin 代码编译为字节码,它不通过办法签名而是通过编译元数据来表白可空性束缚。确保 kotlin-reflect 在您的我的项目中蕴含 JAR 以启用对 Kotlin 的可空性束缚的内省。Spring Data 存储库应用语言机制来定义这些束缚以利用雷同的运行时查看,如下所示:

示例 22. 在 Kotlin 存储库上应用可空性束缚

interface UserRepository : Repository<User, String> {

fun findByUsername(username: String): User

fun findByFirstname(firstname: String?): User?
}
该办法将参数和后果都定义为不可为空(Kotlin 默认值)。Kotlin 编译器回绝传递 null 给办法的办法调用。如果查问产生空后果,
EmptyResultDataAccessException 则抛出 an。

该办法承受 null 的 firstname 参数,并返回 null,如果查问不产生后果。

4.4.8. 流式查问后果
您能够应用 Java 8Stream<T> 作为返回类型以增量形式解决查询方法的后果。不是将查问后果包装在 a 中 Stream,而是应用数据存储特定的办法来执行流式传输,如以下示例所示:

示例 23. 应用 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);
AStream 潜在地包装了底层数据存储特定的资源,因而必须在应用后敞开。您能够 Stream 应用 close()办法或应用 Java 7try-with-resources 块手动敞开,如以下示例所示:

示例 24.Stream<T> 在 try-with-resources 块中处理结果

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
stream.forEach(…);
}
并非所有 Spring Data 模块以后都反对 Stream<T> 作为返回类型。

4.4.9. 异步查问后果
您能够应用 Spring 的异步办法运行能力异步运行存储库查问。这意味着该办法在调用时立刻返回,而理论查问产生在已提交给 Spring 的工作中 TaskExecutor。异步查问不同于反应式查问,不应混合应用。无关反应式反对的更多详细信息,请参阅商店特定的文档。以下示例显示了一些异步查问:

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

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

@Async
ListenableFuture<User> findOneByLastname(String lastname);
应用
java.util.concurrent.Future 作为返回类型。

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

应用
aorg.springframework.util.concurrent.ListenableFuture 作为返回类型。

4.5. 创立存储库实例
本节介绍如何为定义的存储库接口创立实例和 bean 定义。一种办法是应用反对存储库机制的每个 Spring Data 模块附带的 Spring 命名空间,只管咱们通常倡议应用 Java 配置。

4.5.1.XML 配置
每个 Spring Data 模块都蕴含一个 repositories 元素,可让您定义 Spring 为您扫描的根本包,如以下示例所示:

示例 25. 通过 XML 启用 Spring Data 存储库

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans:beans xmlns:beans=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns=”http://www.springframework.org/schema/data/jpa”
xsi:schemaLocation=”http://www.springframework.org/schema/beans

https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<repositories base-package=”com.acme.repositories” />

</beans:beans>
在后面的示例中,批示 Spring 扫描 com.acme.repositories 及其所有子包以查找扩大 Repository 的接口或其子接口之一。对于找到的每个接口,根底构造注册特定 FactoryBean 于持久性技术以创立解决查询方法调用的适当代理。每个 bean 都在从接口名称派生的 bean 名称下注册,因而 的接口 UserRepository 将在 下注册 userRepository。嵌套存储库接口的 Bean 名称以其关闭的类型名称为前缀。该 base-package 属性容许应用通配符,以便您能够定义扫描包的模式。

应用过滤器
默认状况下,基础设施会抉择每个接口,这些接口扩大 Repository 位于配置的根本包下的持久性技术特定的子接口,并为其创立一个 bean 实例。然而,您可能心愿更精密地管制哪些接口为其创立了 bean 实例。为此,请在元素内应用 <include-filter /> 和 <exclude-filter /> 元素 <repositories />。语义齐全等同于 Spring 上下文命名空间中的元素。无关详细信息,请参阅这些元素的 Spring 参考文档。

例如,要将某些接口从实例化中排除为存储库 bean,您能够应用以下配置:

示例 26. 应用 exclude-filter 元素

<repositories base-package=”com.acme.repositories”>
<context:exclude-filter type=”regex” expression=”.*SomeRepository” />
</repositories>
后面的示例排除了所有以 SomeRepository 实例化结尾的接口。

4.5.2.Java 配置
您还能够通过 @Enable${store}Repositories 在 Java 配置类上应用特定于商店的正文来触发存储库根底构造。无关 Spring 容器的基于 Java 的配置的介绍,请参阅 Spring 参考文档中的 JavaConfig。

启用 Spring Data 存储库的示例配置相似于以下内容:

示例 27. 基于注解的存储库配置示例

@Configuration
@EnableJpaRepositories(“com.acme.repositories”)
class ApplicationConfiguration {

@Bean
EntityManagerFactory entityManagerFactory() {

// …

}
}
后面的示例应用特定于 JPA 的正文,您能够依据理论应用的商店模块更改该正文。这同样实用于 EntityManagerFactorybean 的定义。请参阅涵盖商店特定配置的局部。

4.5.3. 独立应用
您还能够在 Spring 容器之外应用存储库基础设施——例如,在 CDI 环境中。您的类门路中依然须要一些 Spring 库,但通常,您也能够通过编程形式设置存储库。提供存储库反对的 Spring Data 模块附带了 RepositoryFactory 您能够应用的特定于持久性技术的技术,如下所示:

示例 28. 存储库工厂的独立应用

RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);
4.6.Spring Data Repositories 的自定义实现
Spring Data 提供了各种选项来创立只需很少编码的查询方法。然而当这些选项不合乎您的需要时,您还能够为存储库办法提供您本人的自定义实现。本节介绍如何做到这一点。

4.6.1. 自定义单个存储库
要应用自定义功能丰富存储库,您必须首先定义片段接口和自定义性能的实现,如下所示:

示例 29. 自定义存储库性能的接口

interface CustomizedUserRepository {
void someCustomMethod(User user);
}
示例 30. 自定义存储库性能的实现

class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

public void someCustomMethod(User user) {

// Your custom implementation

}
}
与片段接口对应的类名中最重要的局部是 Impl 后缀。

实现自身不依赖于 Spring Data,能够是一个一般的 Spring bean。因而,你能够应用规范的依赖注入行为来注入对其余 bean(例如 a JdbcTemplate)的援用,参加方面等等。

而后你能够让你的 repository 接口扩大 fragment 接口,如下:

示例 31. 对存储库界面的更改

interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {

// Declare query methods here
}
应用您的存储库接口扩大片段接口联合了 CRUD 和自定义性能,并使其可供客户端应用。

Spring Data 存储库是通过应用造成存储库组合的片段来实现的。片段是根底存储库、性能方面(例如 QueryDsl)和自定义接口及其实现。每次向存储库界面增加界面时,您都能够通过增加片段来加强组合。每个 Spring Data 模块都提供根本存储库和存储库方面的实现。

以下示例显示了自定义接口及其实现:

示例 32. 片段及其实现

interface HumanRepository {
void someHumanMethod(User user);
}

class HumanRepositoryImpl implements HumanRepository {

public void someHumanMethod(User user) {

// Your custom implementation

}
}

interface ContactRepository {

void someContactMethod(User user);

User anotherContactMethod(User user);
}

class ContactRepositoryImpl implements ContactRepository {

public void someContactMethod(User user) {

// Your custom implementation

}

public User anotherContactMethod(User user) {

// Your custom implementation

}
}
Spring Data JPA 参考文档二
以下示例显示了扩大的自定义存储库的界面 CrudRepository:

示例 33. 对存储库界面的更改

interface UserRepository extends CrudRepository<User, Long>, HumanRepository, ContactRepository {

// Declare query methods here
}
存储库可能由按申明程序导入的多个自定义实现组成。自定义实现比根本实现和存储库方面具备更高的优先级。如果两个片段奉献雷同的办法签名,则此排序容许您笼罩根本存储库和方面办法并解决歧义。存储库片段不限于在单个存储库界面中应用。多个存储库能够应用片段接口,让您能够在不同的存储库中重用自定义。

以下示例显示了存储库片段及其实现:

示例 34. 片段笼罩 save(…)

interface CustomizedSave<T> {
<S extends T> S save(S entity);
}

class CustomizedSaveImpl<T> implements CustomizedSave<T> {

public <S extends T> S save(S entity) {

// Your custom implementation

}
}
以下示例显示了应用上述存储库片段的存储库:

示例 35. 自定义存储库接口

interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}

interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> {
}
配置
如果您应用命名空间配置,存储库根底构造会尝试通过扫描它在其中找到存储库的包下的类来自动检测自定义实现片段。这些类须要遵循将命名空间元素的 repository-impl-postfix 属性附加到片段接口名称的命名约定。此后缀默认为 Impl. 以下示例显示了一个应用默认后缀的存储库和一个为后缀设置自定义值的存储库:

示例 36. 配置示例

<repositories base-package=”com.acme.repository” />

<repositories base-package=”com.acme.repository” repository-impl-postfix=”MyPostfix” />
后面示例中的第一个配置尝试查找一个称为
com.acme.repository.CustomizedUserRepositoryImpl 作为自定义存储库实现的类。第二个示例尝试查找 com.acme.repository.CustomizedUserRepositoryMyPostfix.

解决歧义
如果在不同的包中找到多个具备匹配类名的实现,Spring Data 应用 bean 名称来标识应用哪个。

鉴于 CustomizedUserRepository 后面显示的以下两个自定义实现,应用第一个实现。它的 bean 名称是
customizedUserRepositoryImpl,它与片段 interface(CustomizedUserRepository) 加上后缀的名称相匹配 Impl。

示例 37. 解决不明确的实现

package com.acme.impl.one;

class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

// Your custom implementation
}
package com.acme.impl.two;

@Component(“specialCustomImpl”)
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

// Your custom implementation
}
Spring Data JPA 参考文档二
如果您应用 正文 UserRepository 接口 @Component(“specialCustom”),那么 bean 名称加号 Impl 与 中为存储库实现定义的名称相匹配 com.acme.impl.two,并应用它代替第一个名称。

内容提醒:本文 (Spring Data JPA 参考文档) 未完待续 ……

正文完
 0