SPRING TUTORIAL SPRING TUTORIAL
综合篇
核心篇
数据篇
Web篇
IO篇
集成篇
其他
GitHub (opens new window)
综合篇
核心篇
数据篇
Web篇
IO篇
集成篇
其他
GitHub (opens new window)
  • 框架

    • Spring

      • Spring综合

      • Spring核心

      • Spring数据

        • Spring 之数据源
        • Spring 之 JDBC
        • Spring 之事务
        • Spring 之 JPA
        • Spring 集成 Mybatis
        • Spring Data 综合
          • 核心概念
          • 查询方法
          • 定义 Repository
            • 微调 Repository 定义
            • 使用多个 Spring 数据模块
          • 定义查询方法
            • 查询策略
            • 查询创建
          • 创建 Repository 实例
          • 自定义 Repository 实现
          • Spring Data 扩展
          • 参考资料
        • Spring 访问 Redis
        • Spring 访问 MongoDB
        • Spring 访问 Elasticsearch
      • SpringWeb

      • SpringIO

      • Spring集成

      • Spring安全

      • Spring其他

  • Java
  • 框架
  • Spring
  • Spring数据
dunwu
2023-02-08
目录

Spring Data 综合

# Spring Data 综合

Spring Data Repository 抽象的目标是显著减少各种访问持久化存储的样板式代码。

# 核心概念

Repository 是 Spring Data 的核心接口。此接口主要用作标记接口,以捕获要使用的类型并帮助您发现扩展此接口的接口。CrudRepository 和 ListCrudRepository 接口为被管理的实体类提供复杂的 CRUD 功能。ListCrudRepository 提供等效方法,但它们返回 List,而 CrudRepository 方法返回 Iterable。

CrudRepository 接口定义:

public interface CrudRepository<T, ID> extends Repository<T, ID> {

  <S extends T> S save(S entity);

  Optional<T> findById(ID primaryKey);

  Iterable<T> findAll();

  long count();

  void delete(T entity);

  boolean existsById(ID primaryKey);

  // … more functionality omitted.
}

Spring Data 项目也提供了一些特定持久化技术的抽象接口,如:JpaRepository 或 MongoRepository。这些接口扩展了 CrudRepository 并暴露了一些持久化技术的底层功能。

除了 CrudRepository 之外,还有一个 PagingAndSortingRepository 接口,它添加了额外的方法来简化对实体的分页访问:

public interface PagingAndSortingRepository<T, ID>  {

  Iterable<T> findAll(Sort sort);

  Page<T> findAll(Pageable pageable);
}

【示例】要按页面大小 20 访问 User 的第二页,可以执行如下操作

PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(PageRequest.of(1, 20));

除了查询方法之外,计数和删除时的查询也是可用的。

【示例】根据姓氏计数

interface UserRepository extends CrudRepository<User, Long> {
  long countByLastname(String lastname);
}

【示例】根据姓氏删除

interface UserRepository extends CrudRepository<User, Long> {

  long deleteByLastname(String lastname);

  List<User> removeByLastname(String lastname);
}

# 查询方法

使用 Spring Data 对数据库进行查询有以下四步:

  1. 声明一个扩展 Repository 或其子接口的接口,并指定泛型类型(实体类和 ID 类型),如以下示例所示:

    interface PersonRepository extends Repository<Person, Long> { … }
    
  2. 在接口中声明查询方法

    interface PersonRepository extends Repository<Person, Long> {
      List<Person> findByLastname(String lastname);
    }
    
  3. 使用 JavaConfig (opens new window) 或 XML 配置 (opens new window)为这些接口创建代理实例

    @EnableJpaRepositories
    class Config { … }
    
  4. 注入 Repository 实例并使用

    class SomeClient {
    
      private final PersonRepository repository;
    
      SomeClient(PersonRepository repository) {
        this.repository = repository;
      }
    
      void doSomething() {
        List<Person> persons = repository.findByLastname("Matthews");
      }
    }
    

# 定义 Repository

首先需要定义一个 Repository 接口,该接口必须扩展 Repository 并且指定泛型类型(实体类和 ID 类型)。如果想为该实体暴露 CRUD 方法,可以扩展 CrudRepository 接口。

# 微调 Repository 定义

Spring Data 提供了很多种 Repository 以应对不同的需求场景。

CrudRepository 提供了 CRUD 功能。

ListCrudRepository 和 CrudRepository 类似,但对于那些返回多个实体的方法,它返回一个 List 而不是 Iterable,这样使用可能更方便。

如果使用响应式框架,可以使用 ReactiveCrudRepository 或 RxJava3CrudRepository。

CoroutineCrudRepository 支持 Kotlin 的协程特性。

PagingAndSortingRepository 提供了分页、排序功能。

如果不想扩展 Spring Data 接口,还可以使用 @RepositoryDefinition 注释您的 Repository 接口。 扩展一个 CRUD Repository 接口,需要暴露一组完整的方法来操作实体。如果希望对暴露的方法有选择性,可以将要暴露的方法从 CRUD Repository 复制到自定义的 Repository 中。 这样做时,可以更改方法的返回类型。 如果可能,Spring Data 将遵循返回类型。 例如,对于返回多个实体的方法,可以选择 Iterable<T>、List<T>、Collection<T> 或 VAVR 列表。

自定义基础 Repository 接口,必须用 @NoRepositoryBean 标记。 这可以防止 Spring Data 尝试直接创建它的实例并失败,因为它无法确定该 Repository 的实体,因为它仍然包含一个通用类型变量。

以下示例显示了如何有选择地暴露 CRUD 方法(在本例中为 findById 和 save):

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends Repository<T, ID> {

  Optional<T> findById(ID id);

  <S extends T> S save(S entity);
}

interface UserRepository extends MyBaseRepository<User, Long> {
  User findByEmailAddress(EmailAddress emailAddress);
}

# 使用多个 Spring 数据模块

有时,程序中需要使用多个 Spring Data 模块。在这种情况下,必须区分持久化技术。当检测到类路径上有多个 Repository 工厂时,Spring Data 进入严格的配置模式。

如果定义的 Repository 扩展了特定模块中的 Repository,则它是特定 Spring Data 模块的有效候选者。

如果实体类使用了特定模块的类型注解,则它是特定 Spring Data 模块的有效候选者。 Spring Data 模块接受第三方注解(例如 JPA 的 @Entity)或提供自己的注解(例如用于 Spring Data MongoDB 和 Spring Data Elasticsearch 的 @Document)。

以下示例显示了一个使用模块特定接口(在本例中为 JPA)的 Repository:

interface MyRepository extends JpaRepository<User, Long> { }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }

interface UserRepository extends MyBaseRepository<User, Long> { … }

MyRepository 和 UserRepository 扩展了 JpaRepository。它们是 Spring Data JPA 模块的有效候选者。

以下示例显示了一个使用通用接口的 Repository

interface AmbiguousRepository extends Repository<User, Long> { … }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }

interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { … }

AmbiguousRepository 和 AmbiguousUserRepository 仅扩展了 Repository 和 CrudRepository。 虽然这在使用唯一的 Spring Data 模块时很好,但是存在多个模块时,无法区分这些 Repository 应该绑定到哪个特定的 Spring Data。

以下示例显示了一个使用带注解的实体类的 Repository

interface PersonRepository extends Repository<Person, Long> { … }

@Entity
class Person { … }

interface UserRepository extends Repository<User, Long> { … }

@Document
class User { … }

PersonRepository 引用 Person,它使用 JPA @Entity 注解进行标记,因此这个 Repository 显然属于 Spring Data JPA。 UserRepository 引用 User,它使用 Spring Data MongoDB 的 @Document 注解进行标记。

以下错误示例显示了一个使用带有混合注解的实体类的 Repository

interface JpaPersonRepository extends Repository<Person, Long> { … }

interface MongoDBPersonRepository extends Repository<Person, Long> { … }

@Entity
@Document
class Person { … }

此示例中的实体类同时使用了 JPA 和 Spring Data MongoDB 的注解。示例中定义了两个 Repository:JpaPersonRepository 和 MongoDBPersonRepository。 一个用于 JPA,另一个用于 MongoDB。 Spring Data 不再能够区分 Repository,这会导致未定义的行为。

区分 Repository 的最后一种方法是确定 Repository 扫描 package 的范围。

@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }

# 定义查询方法

Repository 代理有两种方法可以从方法名称派生特定于存储的查询:

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

可用选项取决于实际存储。但是,必须有一个策略来决定创建什么实际查询。

# 查询策略

以下策略可用于Repository 基础结构来解析查询。 对于 Java 配置,您可以使用 EnableJpaRepositories 注释的 queryLookupStrategy 属性。 特定数据存储可能不支持某些策略。

  • CREATE 尝试从查询方法名称构造特定存储的查询。
  • USE_DECLARED_QUERY 尝试查找已声明的查询,如果找不到则抛出异常。
  • CREATE_IF_NOT_FOUND (默认)结合了 CREATE 和 USE_DECLARED_QUERY。

# 查询创建

Spring Data 中有一套内置的查询构建器机制,可以自动映射符合命名和参数规则的方法。

interface PersonRepository extends Repository<Person, Long> {

  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enables the distinct flag for the query
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

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

  // Enabling static ORDER BY for a query
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

解析查询方法名称分为主语和谓语。第一部分 (find…By, exists…By) 定义查询的主语,第二部分构成谓词。 主语可以包含更多的表达。 find(或其他引入关键字)和 By 之间的任何文本都被认为是描述性的,除非使用其中一个结果限制关键字,例如 Distinct 在要创建的查询上设置不同的标志或 Top/First 限制查询结果。

参考:

Spring Data 支持的查询主语关键词 (opens new window)

Spring Data 支持的查询谓语关键词 (opens new window)

# 创建 Repository 实例

# 自定义 Repository 实现

# Spring Data 扩展

# 参考资料

  • Redis 官网 (opens new window)
  • Redis Github (opens new window)
  • spring-data-redis Github (opens new window)
  • Spring Data Redis 官方文档 (opens new window)
  • Spring Data 官方示例 (opens new window)
📝 帮助改善此页面! (opens new window)
#Java#框架#Spring#SpringBoot
上次更新: 2024/04/24, 07:33:33
Spring 集成 Mybatis
Spring 访问 Redis

← Spring 集成 Mybatis Spring 访问 Redis→

最近更新
01
Spring MVC 之视图技术
02-17
02
Spring MVC 之跨域
02-16
03
Spring Web 应用
02-14
更多文章>
Theme by Vdoing | Copyright © 2019-2024 钝悟(dunwu) | CC-BY-SA-4.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×