Spring Data 仓库抽象的目标是为了明显减少为了各种持久存储的来实现的数据访问层的样板代码量。
Spring Data存储库文档和你的模块
本章解释了Spring Data 存储库的核心观念,以及接口。本章的信息来自Spring Data公共模块。它使用了Java Persistence API(JPA)中的配置以及代码实例。将命名空间声明和要扩展的类型扩展为你将会使用的模块的等效项。命名空间引用包含了所有被Spring Data模块支持的存储库API的XML配置,存储库查询关键字包含了常用的存储库抽象所支持的查询方法关键字。对于模块特定特性的详细信息,参阅文档中讲述该模块的章节。
4.1 核心观点
在Spring Data 抽象中中心接口就是Repository(没有多大意外)。它使用域类来管理以及将域类的id类型作为类型参数。这个接口主要作为标记的接口来捕捉工作的类型并且帮助你去发现被扩展的接口。CrudRepository 提供了复杂的CRUD功能给以及被管理的实体类。
public interface CrudRepository<T, ID extends Serializable>extends Repository<T, ID> {
<S extends T> S save(S entity); //1
T findOne(ID primaryKey); //2
Iterable<T> findAll(); //3
Long count(); //4
void delete(T entity); //5
boolean exists(ID primaryKey); //6
// … more functionality omitted.
}
1.保存实体。
2.返回给定标识符的实体。
3.返回全部实体。
4.返回实体的个数。
5.删除给定的实体。
6.表明给定ID的实体是否存在。
我们仍然提供技术指定的持久层抽象,比如JpaRepository 或者 MongoRepository。这些接口扩展了CrudRepository 并且比起通用的持久层与技术无关的接口比如CrudRepository来说暴露了另外的底层的持久层技术功能。
在CrudRepository上层有一个PagingAndSortingRepository抽象添加了另外的方法来轻松使用分页的方式访问实体。
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<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(new PageRequest(1, 20));
除了查询方法,查询导出计数和删除查询都是可用的。
例子3:查询导出计数
public interface UserRepository extends CrudRepository<User, Long> {
Long countByLastname(String lastname);
}
例子4 查询删除
public interface UserRepository extends CrudRepository<User, Long> {
Long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
4.2 查询方法
标准的CRUD功能性存储库通常在底层的数据库里有查询。在SpringData 中声明这些查询通常有四步:
1.声明一个扩展了Respository或者它的子接口并且设置了它的域类和Id类型的接口。
interface PersonRepository extends Repository<Person, Long> { … }
2.声明这个接口的查询方法
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLastname(String lastname);
}
3.设置Spring为这些接口创建代理实例.可以用JavaConfig
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories
class Config {}
或者使用XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="com.acme.repositories"/>
</beans>
这个例子中使用的是JPA的命名空间。如果你要使用其他的存储库抽象,你需要替换jpa为合适的存储模块的命名空间声明比如mongodb。
同时,注意JavaConfig变量不会显示配置包而是默认使用注释类的包。使用数据存储特定的存储库@Enable…-注解的basePackage属性来自定义要扫描的包。
4.注入存储库的实例并且使用它:
public class SomeClient {
@Autowired
private PersonRepository repository;
public void doSomething() {
List<Person> persons = repository.findByLastname("Matthews");
}
}
接下来的章节解释了每一步的细节。
4.3 定义存储库接口
作为第一步你定义一个域指定类存储库接口。这个接口必须扩展自Repository,并键入到域类和ID类型。如果你想要暴露CRUD方法给域类型可以扩展CrudRepository而不是Repository。
###4.3.1 微调存储库的定义
一般来说你的存储库接口会扩展自Repository,CrudRepository或者PagingAndSortingRepository。但是如果你不想要扩展Spring Data的接口,你可以通过使用@RepositoryDefinition注入你自己的存储库接口。扩展CrudRepository 暴露了一系列完整的方法来操控你的实体。如果你偏向于对与暴露的方法有选择性,简单的从CrudRepository复制对应的方法到你的域存储库中。
这个允许你在提供的Spring Data 存储库的功能之上定义你自己的抽象
例子5.选择性暴露CRUD方法
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
T save(T entity);
}
interface UserRepository extends MyBaseRepository<User, Long> {
User findByEmailAddress(EmailAddress emailAddress);
}
在第一步你定义了一个基本的接口给你全部的域存储同时暴露了findOne()和Save()两个方法。这些方法将会被路由到你选择的由SpringData提供的存储的基础的存储库实现,比如如果是JPA 就是SimpleJpaRepository,因为他们满足在CrudRepository中的方法标签。所以UserRepository现在可以存储用户,根据id来查找指定用户,或者触发一个按照他们的邮件地址的查询。
注意中间的存储库接口由@NoRepositoryBean注解表示。确保你添加了这个注解给所有的存储库接口,这样Spring Data不会在运行时创建实例。
4.4.2 对多个Spring Data模块使用存储库
在应用中使用一个唯一的Spring Data 模块可以使事情简单,因此所有在定义范围内的存储库接口都被绑定到Spring Data 模块。有时应用要求使用一个以上的Spring Data 模块。在这个情况下,要求存储库的定义可以分辨不同的存储层技术。由于可以检测到多个存储库工厂在类路径中,Spring Data 使用严格的存储库配置模式。严格的配置需要存储库的细节或者域类来决定Spring Data 模块绑定一个存储库的定义:
1.如果存储库定义扩展指定模块的存储库,那么它是一个合格的对于特定的Spring Data 模块的候选者。
2.如果域类是由模块特定的类型注解来注解的,那么它是一个合格的对于特定的Spring Data 模块的候选者。Spring Data 模块接受第三方的注解(比如JPA的 @Entity)或者提供自己的注解比如@Document用于Spring Data MongoDB/Spring Data Elasticsearch。
例子6 使用指定模块的接口定义的存储库
interface MyRepository extends JpaRepository<User, Long> { }
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
…
}
interface UserRepository extends MyBaseRepository<User, Long> {
…
}
MyRepository和UserRepository扩展JpaRepository在他们的类型层级中。他们是Spring Data JPA模块的合法的候选人。
例子7 使用通用接口定义的存储库
interface AmbiguousRepository extends Repository<User, Long> {
…
}
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
…
}
interface AmbiguousUserRepository extends MyBaseRepository<User, Long> {
…
}
AmbiguousRepository和AmbiguousUserRepository只扩展了Repository和CrudRepository在它们的类型层级中。虽然这是完全正确的使用一个唯一的Spring Data模块,多模块没法辨识这个存储库应该绑定哪一个特定的Spring Data。
例子8 使用注解域类定义的存储库
interface PersonRepository extends Repository<Person, Long> {
…
}
@Entity
public class Person {
…
}
interface UserRepository extends Repository<User, Long> {
…
}
@Document
public class User {
…
}
由于PersonRepository 引用使用JPA注解@Entity注解的Person,这个存储库清楚的属于Spring Data JPA。UserRepository使用Spring Data MongoDB的@Document注解的User类。
例子9 使用注解和域类混合的存储库定义
interface JpaPersonRepository extends Repository<Person, Long> {
…
}
interface MongoDBPersonRepository extends Repository<Person, Long> {
…
}
@Entity
@Document
public class Person {
…
}
这个例子展示一个域类使用了JPA和MongoDb的注解。它定义了两个存储库,JpaPersonRepository和MongoDBPersonRepository.一个给JPA,一个给MongoDB使用。Spring Data 不能分辨出存储库,将会导致未定义的行为。
存储库类型细节和分辨域类注解用于严格的存储库配置对一个Spring Data 模块来区分存储库候选人。在相同的域类型中使用多个持久层技术注解可以重用域类型来访问多持久层技术,但是Spring Data 不再可以决定一个特定的模块绑定到存储库。
最后一个方法来区分存储库是作用域基础包。基础包定义了开始点用来扫描哪些存储库接口在合适的包中实现了存储库的定义。默认的注解驱动配置使用了配置类的包。这个使用XML基础配置的基础包是强制性的。
例子10 基础包的注解驱动配置
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
interface Configuration { }
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/113895.html