主要译自:
https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#repositories
https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.repositories
8. Working with Spring Data Repositories
本章解释了Spring Data存储库的核心概念和接口。
一言蔽之,Spring Data repository抽象的目标就是——减少重复的模板代码。
8.1. Core concepts
Spring Data repository抽象(abstraction)的中心接口是repository。它将域类(domain class)以及域类的ID类型作为类型参数(type arguments)进行管理。此接口主要用作标记接口,用于捕获要使用的类型,并帮助您发现继承(extend)此类型的接口。Crudepository接口为正在管理的实体类(the entity class)提供复杂的CRUD功能。
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. }
从上往下的注释:
- 保存给定的实体。(对应<S extends T> S save(S entity);)
- 返回由给定ID标识的实体。
- 返回所有实体。
- 返回实体数。
- 删除给定的实体。
- 指示具有给定ID的实体是否存在。
我们还提供特定于持久性技术的抽象,如JpaRepository或MongoRepository。这些接口扩展(extend)了Crudepository,并公开了底层持久性技术的功能,以及与持久性技术无关的通用接口,如CrudRepository。
在CrudRepository之上,还有一个PagingAndSortingRepository抽象,它添加了其他方法,以简化对实体的分页访问:(见原文)
除了查询方法外,还可以对计数和删除查询进行查询派生(query derivation)。下表显示了派生(derived )计数查询的接口定义:
interface UserRepository extends CrudRepository<User, Long> { long countByLastname(String lastname); }
8.2. Query Methods
标准CRUD功能存储库通常对底层数据存储进行查询。使用Spring数据,声明这些查询将变成一个四步过程:
①声明一个接口继承Repository或其子接口之一,并将其键入应处理的域类(domain class)和ID类型,如以下示例所示:
interface PersonRepository extends Repository<Person, Long> { … }
②在接口上声明查询方法。
interface PersonRepository extends Repository<Person, Long> { List<Person> findByLastname(String lastname); }
③设置Spring,使用JavaConfig或XML配置为这些接口创建代理实例(proxy instances)。(详见文档)
④注入存储库实例(the repository instance)并使用它,如下例所示:
class SomeClient { private final PersonRepository repository; SomeClient(PersonRepository repository) { this.repository = repository; } void doSomething() { List<Person> persons = repository.findByLastname("Matthews"); } }
9. JDBC Repositories
本章指出了JDBC存储库支持的特点。这建立在“Working with Spring Data Repositories”中介绍的核心存储库支持的基础上。你应该对这里解释的基本概念有很好的理解。
9.1. Why Spring Data JDBC?
Java世界中关系数据库的主要持久化API当然是JPA,它有自己的Spring数据模块。为什么还有另一个?
JPA做了很多事情来帮助开发者。除此之外,它还跟踪实体的变化。它为您提供了惰性加载。它允许您将大量对象构造映射到同样广泛的数据库设计。
这很好,让很多事情变得非常简单。请看一个基本的JPA教程。但对于JPA为什么要做某件事,人们往往会感到困惑。而且,在JPA中,概念上非常简单的事情变得相当困难。
Spring Data JDBC的目标是在概念上更加简单,包括以下设计决策:
- 如果加载实体,SQL语句就会运行。完成后,就有了一个完全加载的实体。没有进行延迟加载或缓存。
- 如果保存一个实体,它将被保存。如果你不这样做,它就不会。没有肮脏的跟踪和会话。
- 关于如何将实体映射到表,有一个简单的模型。它可能只适用于相当简单的情况。如果你不喜欢这样,你应该编写自己的策略。Spring Data JDBC对使用注释定制策略的支持非常有限。
9.2. Domain Driven Design and Relational Databases.
所有Spring数据模块都受到域驱动设计(DDD)中“存储库”、“聚合”和“聚合根”概念的启发。这些对于Spring Data JDBC可能更重要,因为它们在某种程度上与处理关系数据库时的常规做法相反。
聚合(aggregate)是一组实体,保证在对其进行原子更改时保持一致。一个典型的例子是带有OrderItems的Order。Order上的属性(例如,numberOfItems与OrderItems的实际数量一致)在进行更改时保持一致。
聚合之间的引用(References)并不保证一直都是一致的。但他们保证最终会是一致的。
每个聚合有且仅有一个聚合根(aggregate root),它是聚合的一个实体。仅通过聚合根上的方法对聚合进行操作。这些是前面提到的原子变化。
存储库(repository)是持久化存储的抽象,它看起来像是某个类型的所有聚合的集合。对于一般的Spring Data,这意味着您希望每个聚合根都有一个Repository。此外,对于Spring Data JDBC,这意味着从聚合根可访问的所有实体都被认为是该聚合根的一部分。Spring Data JDBC假设只有聚合具有存储聚合的非根实体的表的外键,并且没有其他实体指向非根实体。(????)
在当前的实现中,Spring Data JDBC删除并重新创建从聚合根引用的实体。
您可以使用与您的工作和设计数据库的风格相匹配的实现来覆盖存储库方法。
9.3. Getting Started
引导设置工作环境的一种简单方法是在STS或Spring Initializer中创建一个基于Spring的项目。
首先,您需要设置一个正在运行的数据库服务器。有关如何为JDBC访问配置数据库的信息,请参阅供应商文档。
9.4. Examples Repository
https://github.com/spring-projects/spring-data-examples
9.5. Annotation-based Configuration
Spring Data JDBC存储库支持可以通过Java配置的注释激活,如下例所示:
@Configuration @EnableJdbcRepositories // 为从Repository派生的接口创建实现 class ApplicationConfig extends AbstractJdbcConfiguration { // 提供Spring Data JDBC所需的各种默认bean @Bean DataSource dataSource() { // 创建连接到数据库的数据源。 // 这是以下两种bean方法所必需的。 EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.HSQL).build(); } @Bean NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) { // 创建Spring Data JDBC用于访问数据库的NamedParameterJDBC操作 return new NamedParameterJdbcTemplate(dataSource); } @Bean TransactionManager transactionManager(DataSource dataSource) { // Spring Data JDBC利用Spring JDBC提供的事务管理。 return new DataSourceTransactionManager(dataSource); } }
前面示例中的配置类通过使用spring-jdbc的EmbeddedDatabaseBuilder API建立嵌入式HSQL数据库。然后使用DataSource设置NamedParameterJdbcOperations和TransactionManager。最后,我们使用@EnableJdbcRepositories激活Spring Data JDBC存储库。如果没有配置基本包,它将使用配置类所在的包。扩展AbstractJdbcConfiguration可确保注册各种bean。覆盖其方法可用于自定义设置(见下文)。
使用Spring Boot可以进一步简化此配置。在Spring Boot中,一旦spring-boot-starter-data-jdbc包含在依赖项中,数据源就足够了。其他一切都由Spring Boot完成。
在这个设置中,可能需要定制一些东西。