续上文

1.4、定义方法

  存储库代理有两种方法可以从方法名称派生特定于存储的查询。它可以直接从方法名称派生查询,或者使用手动定义的查询。可用选项取决于实际store。但是,必须有一个策略来决定创建什么样的实际查询。我们来看看可用的选项。

1.4.1、查询策略

  以下策略可用于存储库基础结构来解析查询。在配置XML配置的情况下,您可以通过query-lookup-strategy属性在命名空间配置策略,或者在Java配置的情况下通过Enable $ {store}存储库注释的queryLookupStrategy属性来配置策略。某些策略可能不支持特定的数据存储。

  CREATE:尝试从查询方法名称构造特定于store的查询。一般的方法是从方法名称中移除一组已知的前缀,并解析该方法的其余部分。详细看1.4.2

  USE_DECLARED_QUERY会尝试查找已声明的查询,并在发现异常时会抛出异常。查询可以通过某处的注释或其他方式声明。查阅特定Store的文档以查找该Store​​的可用选项。如果存储库基础结构在引导时未找到该方法的已声明查询,则会失败。

  CREATE_IF_NOT_FOUND(默认)结合了CREATE和USE_DECLARED_QUERY。它首先查找已声明的查询,如果未找到已声明的查询,则会创建一个基于自定义方法名称的查询。这是默认的查找策略,因此如果您没有明确配置任何内容,将会使用它。它允许通过方法名称进行快速查询定义,还可以根据需要引入已声明的查询来自定义这些查询。

1.4.2、查询创建

  构建到Spring Data存储库基础结构中的查询构建器机制对构建存储库实体上的约束查询非常有用。该机制剥离前缀find... By,read ... By,query ... By,count ... By,get... By方法并开始解析其余部分。引入子句可以包含更多表达式,例如在要创建的查询上设置不同的标志。但是,第一个By作为分隔符来指示实际标准的开始。在非常基本的层次上,您可以定义实体属性的条件,并将它们与And和Or连接起来。

示例、从方法名称创建查询

interface PersonRepository extends Repository<User, 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);
}

解析方法的实际结果取决于您为其创建查询的持久性存储。但是,有一些一般的事情需要注意。

  表达式通常是属性遍历和可以连接的运算符。您可以将属性表达式与AND和OR结合使用。您还可以获得对诸如Between,LessThan,GreaterThan等运算符的支持,就像属性表达式一样。

  方法解析器支持为各个属性设置IgnoreCase标志(例如,findByLastnameIgnoreCase(...))或支持忽略大小写的类型的所有属性(通常是String实例,例如findByLastnameAndFirstnameAllIgnoreCase(...))

  您可以通过将OrderBy子句附加到引用属性的查询方法并提供排序方向(Asc或Desc)来应用静态排序。

1.4.3、属性表达式

  属性表达式只能引用被管实体的直接属性,如上例所示。在查询创建时,您已经确保解析的属性是托管域类的属性。但是,您也可以通过遍历嵌套属性来定义约束。假设一个人有一个ZipCode的地址。在这种情况下,方法名称为

List<Person> findByAddressZipCode(ZipCode zipCode);

  创建属性遍历x.address.zipCode。解析算法首先将整个部分(AddressZipCode)解释为属性,然后检查domain类是否具有该名称的属性(未包含大小)。如果算法成功,则使用该属性。如果不是这样,该算法将来自右侧的骆驼案件部分的来源拆分为头部和尾部,并尝试查找相应的属性,在我们的示例AddressZip和Code中。如果算法找到具有该头部的属性,它将采用尾部并从该处继续构建树,然后按照刚刚描述的方式分割尾部。如果第一次拆分不匹配,则算法将拆分点移到左侧(地址,ZipCode)并继续。

  虽然这应该适用于大多数情况,但算法可能会选择错误的属性。假设Person类也有addressZip属性。该算法将在第一轮拆分中匹配,并且基本上选择错误的属性并最终失败(因为addressZip的类型可能没有代码属性)。

  要解决这种歧义,您可以在方法名称中使用\ _手动定义遍历点。所以我们的方法名称会像这样结束:

List<Person> findByAddress_ZipCode(ZipCode zipCode);

  当我们将下划线看作保留字符时,我们强烈建议遵循标准的Java命名约定(即不要在属性名称中使用下划线,而应使用骆驼大小写)。

1.4.4、特殊参数处理

  要处理查询中的参数,只需定义方法参数,如上例中已经看到的那样。除此之外,基础结构还会识别某些特定类型(如Pageable和Sort),以便动态地将分页和排序应用于查询。

示例、使用Pageable,Slice和Sort in查询方法

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);

  第一种方法允许您将org.springframework.data.domain.Pageable实例传递给查询方法,以动态地将分页添加到静态定义的查询中。一个Page知道可用的元素和页面的总数。它通过基础设施触发计数查询来计算总数。由于这可能会很昂贵,具体取决于所使用的store,因此Slice可以用作替代。Slice只知道是否有下一个Slice可用,这在遍历更大的结果集时可能就足够了。

  排序选项也是通过Pageable实例处理的。如果您只需要排序,只需在您的方法中添加org.springframework.data.domain.Sort参数。正如你所看到的,简单地返回一个List也是可能的。在这种情况下,将不会创建构建实际Page实例所需的附加元数据(这又意味着额外的计数查询本来是必需的而不是被发出)而只是简单地限制查询只查找给定范围的实体。

  要找出完整查询得到的页数,您必须触发额外的计数查询。默认情况下,此查询将从您实际触发的查询中派生。

1.4.5、限定条数查询

  查询方法的结果可以通过关键字first或top来限制,这些关键字可以互换使用。一个可选的数字值可以被附加到top / first,以指定要返回的最大结果大小。如果该数值被忽略,则假定结果大小为1。

示例、用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关键字。此外,对于将结果集限制为一个实例的查询,支持将结果包装为可选。

  如果将分页或切片应用于限制查询分页(以及计算可用页面的数量),则将其应用于有限的结果中。

  注意,通过Sort参数与动态排序结合限制结果,可以表达“K”最小以及“K”最大元素的查询方法。

1.4.6、流查询

  查询方法的结果可以通过使用Java 8 Stream <T>作为返回类型进行递增处理。而不是简单地将查询结果包装到Stream数据存储中,而是使用特定的方法来执行流式传输。

示例、用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);

  Stream可能包装底层数据存储特定资源,因此必须在使用后关闭。您可以使用close()方法手动关闭流,也可以使用Java 7 try-with-resources块。

示例、try-with-resources块关闭 Stream <T>流

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
stream.forEach(…);
}

并非所有的Spring Data模块当前都支持Stream <T>作为返回类型。

1.4.7、异步查询Async

  使用Spring的异步方法执行功能可以异步执行store查询。这意味着方法将在调用时立即返回,并且实际的查询执行将发生在已提交给Spring TaskExecutor的任务中。

//java.util.concurrent.Future
@Async
Future<User> findByFirstname(String firstname);
//Java 8 java.util.concurrent.CompletableFuture
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
//org.springframework.util.concurrent.ListenableFuture
@Async
ListenableFuture<User> findOneByLastname(String lastname);

1.5、创建repository实例

  将为定义的存储库接口创建实例和bean定义。一种方法是使用每个支持存储库机制的Spring Data模块附带的Spring命名空间,尽管我们通常推荐使用Java-Config样式配置。

1.5.1、XML配置

  每个Spring Data模块都包含一个repositories元素,它允许您简单地定义Spring为您扫描的基本包。

示例、通过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
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"> <repositories base-package="com.acme.repositories" /> </beans:beans>

  在前面的例子中,Spring被指示扫描com.acme.repositories及其所有子包,用于扩展Repository或其子接口之一的接口。对于找到的每个接口,基础设施注册持久性技术特定的FactoryBean以创建处理调用查询方法的适当代理。每个bean都是在从接口名称派生的bean名称下注册的,因此UserRepository的接口将注册在userRepository下。base-package属性允许使用通配符,以便您可以定义扫描包的模式。

使用filters

示例、使用排除过滤器元素

<repositories base-package="com.acme.repositories">
<context:exclude-filter type="regex" expression=".*SomeRepository" />
</repositories>

这个例子排除了所有以SomeRepository结尾的接口被实例化的接口。

1.5.2、JavaConfig

可以使用特定于@ Enable $ {store} Repositories注释在JavaConfig类上触发

@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration { @Bean
EntityManagerFactory entityManagerFactory() {
// …
}
}

1.5.3、独立使用

  您还可以使用Spring容器之外的存储库基础结构,例如在CDI环境中。你的类路径中仍然需要一些Spring库,但通常你也可以通过编程来设置库。提供存储库支持的Spring Data模块提供了一个您可以使用的持久性技术特定的RepositoryFactory,如下所示。

示例

RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);

1.6、Spring Data存储库的自定义实现

1.6.1、定制个人存储

首先要为定制功能定义一个片段接口和一个实现。然后让您的存储库接口从片段接口扩展。

示例、定制存储库功能的接口和实现

interface CustomizedUserRepository {
void someCustomMethod(User user);
}
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

  public void someCustomMethod(User user) {
// Your custom implementation
}
}

要找到的类的最重要的位是与片段接口相比较的名称的Impl后缀。

  实现本身不依赖于Spring Data,可以是普通的Spring bean。因此,您可以使用标准的依赖注入行为来注入对其他bean的引用

  更改您的存储库接口

interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {
// Declare query methods here
}

让您的存储库接口扩展一个片段。这样做结合了CRUD和自定义功能,并使其可供客户使用。

  Spring数据存储库通过使用构成存储库组合的片段来实现。片段是基础知识库,QueryDsl和自定义接口等功能方面及其实现。每次将接口添加到存储库接口时,都会通过添加片段来增强组合。每个Spring Data模块提供基础知识库和存储库方面的实现。

示例、实现片段

interface HumanRepository {
void someHumanMethod(User user);
} class HumanRepositoryImpl implements HumanRepository { public void someHumanMethod(User user) {
// Your custom implementation
}
} interface EmployeeRepository { void someEmployeeMethod(User user); User anotherEmployeeMethod(User user);
} class ContactRepositoryImpl implements ContactRepository { public void someContactMethod(User user) {
// Your custom implementation
} public User anotherContactMethod(User user) {
// Your custom implementation
}
}

更改存储接口

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

  // Declare query methods here
}

  存储库可能由多个自定义实现组成,这些自定义实现按其声明的顺序导入。自定义实现具有比基本实现和存储库方面更高的优先级。此排序允许您覆盖基本存储库和方面方法,并在两个片段提供相同的方法签名时解决歧义。存储库片段不限于在单个存储库接口中使用。多个存储库可以使用分段界面来重复使用跨不同存储库的定制。

示例、覆盖 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
}
}

自定义

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

配置

  如果使用命名空间配置,则存储库基础结构会尝试通过扫描我们找到存储库所在的软件包下的类来自动检测自定义实施片段。这些类需要遵循将名称空间元素的属性repository-impl-postfix追加到找到的碎片接口名称的命名约定。这个后缀默认为Impl。

  示例

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

<repositories base-package="com.acme.repository" repository-impl-postfix="FooBar" />

  第一个配置示例将尝试查找类com.acme.repository.CustomizedUserRepositoryImpl作为自定义存储库实现,而第二个示例将尝试查找com.acme.repository.CustomizedUserRepositoryFooBar

解决歧义

  如果在不同的包中找到具有匹配类名的多个实现,则Spring Data使用这些bean名来标识要使用的正确类。鉴于上面介绍的CustomizedUserRepository的以下两个自定义实现,第一个实现将被选中。它的bean名称是customizedUserRepositoryImpl,它与分片接口的名称相匹配(CustomizedUserRepository)加上后缀Impl。

示例、

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
}

如果使用@Component(“specialCustom”)对UserRepository接口进行注释,那么bean名称加上Impl与为com.acme.impl.two中的存储库实现定义的接口相匹配,它将被选中而不是第一个。

手工接入实现

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

<beans:bean id="userRepositoryImpl" class="…">
<!-- further configuration -->
</beans:bean>

1.6.2、自定义基础存储库

自定义存储库基类

class MyRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> { private final EntityManager entityManager; MyRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager); // Keep the EntityManager around to used from the newly introduced methods.
this.entityManager = entityManager;
} @Transactional
public <S extends T> S save(S entity) {
// implementation goes here
}
}

最后一步是让Spring Data基础设施知道定制的存储库基类。在JavaConfig中,这是通过使用@ Enable ... Repositories注释的repositoryBaseClass属性来实现的:

使用JavaConfig配置定制存储库基类

@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }

或者使用XML配置自定义存储库基类

<repositories base-package="com.acme.repository" base-class="….MyRepositoryImpl" />

1.7、从聚合根发布事件

地址:查看

004-spring-data-elasticsearch 3.0.0.0使用【二】-spring-data之定义方法、创建repository实例、从聚合根发布事件的更多相关文章

  1. spring容器初始化bean和销毁bean之前进行一些操作的定义方法

    关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种:        第一种,通过在xml中定义init-method和destory-method方法        第二种, ...

  2. spring整合elasticsearch之环境搭建

    推荐一个非常好的博客: 点我 // 测试使用docker下启动的es不管用, 在linux下或者windows下运行的es可用 // 进一步测试docker下启动的es链接时, 开启嗅探也链接不上, ...

  3. Spring容器中bean的生命周期以及关注spring bean对象的后置处理器:BeanPostProcessor(一个接口)

    Spring IOC 容器对 Bean 的生命周期进行管理的过程: 1.通过构造器或工厂方法创建 Bean 实例 2.为 Bean 的属性设置值和对其他 Bean 的引用 3.将 Bean 实例传递给 ...

  4. Spring 工厂方法创建Bean 学习(三)

    1, 静态工厂方法创建Bean 调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节. 要声明通过静态方法创建 ...

  5. spring boot 2.0 整合 elasticsearch6.5.3,spring boot 2.0 整合 elasticsearch NoNodeAvailableException

    原文地址:spring boot 2.0 整合 elasticsearch NoNodeAvailableException 原文说的有点问题,下面贴出我的配置: 原码云项目地址:https://gi ...

  6. ElasticsearchException: java.io.IOException: failed to read [id:0, file:/data/elasticsearch/nodes/0/_state/global-0.st]

    from : https://www.cnblogs.com/hixiaowei/p/11213143.html 1.以前装过elasticsearch,重新安装elastic search ,报错 ...

  7. 001-快速搭建Spring web应用【springboot 2.0.4】-gradle、springboot的启动过程分析、gradle多模块构建

    一.概述 学习<精通Spring MVC4>书籍笔记 二.笔记 1.快速构建Spring starter web项目几种方式 1>使用Spring Tool Suite生成Start ...

  8. spring boot 2.0.3+spring cloud (Finchley)9、 安全组件Spring Boot Security

    官方文档 一.Spring Security介绍 Spring Security是Spring Resource社区的一个安全组件,Spring Security为JavaEE企业级开发提供了全面的安 ...

  9. 《从0到1学习Flink》—— Data Sink 介绍

    前言 再上一篇文章中 <从0到1学习Flink>-- Data Source 介绍 讲解了 Flink Data Source ,那么这里就来讲讲 Flink Data Sink 吧. 首 ...

随机推荐

  1. Jafka源码分析——网络架构

    在kafka中.每个broker都是一个server.依照一般理解,server就是一个SocketServer,其不断接收用户的请求并进行处理.在Java中进行网络连接有两种方式一种为堵塞模式一种为 ...

  2. 看完阮一峰的React教程后, 我写了一个TodoList

    看完阮一峰的React教程后,就自己做了这个TodoList,自己慢慢琢磨效率差了点但是作为入门小练习还是不错的. 以下是效果图:我的源码:todolistUI:bootstrap 4 一.组件化 我 ...

  3. FPGA引脚锁定 注意err和高阻状态

    1.fpga没有用的的管脚一定要设置成高阻状态设置路径如下: Assignmen->Device->Device&Pin Option->Unused pins->As ...

  4. centos 7 安装 nginx 或 apache,及其比较

    来自 知乎 陈湛翀 的回答:https://www.zhihu.com/question/19571087/answer/12313829 nginx 和 apache 比较 nginx 相对 apa ...

  5. Mongo--02 命令介绍

    目录 Mongo工具 1. 查看指令 2.插入命令 3.查询命令 4.更新数据 5.索引 5.删除 6.mongo命令介绍 7.创建用户和角色 Mongo工具 1. 查看指令 test:登录时默认存在 ...

  6. 2019 ACM/ICPC 全国邀请赛(西安)J And And And (树DP+贡献计算)

    Then n - 1n−1 lines follow. ii-th line contains two integers f_{a_i}(1 \le f_{a_i} < i)fai​​(1≤fa ...

  7. Ubuntu 下串口调试工具

    1. cutecom 安装:sudo apt-get install cutecom 打开方式: 在终端输入:cutecom,即可打开串口工具 或者在应用中,点击 cutecom 图标打开 打开后的界 ...

  8. 用Java写一个递归遍历目录下面的所有文件

    java获取文件的属性如文件大小和修改时间: long mysize = file.length();long lastModified = file.lastModified();System.ou ...

  9. Ubuntu 压缩文件命令

    tar -czvf name-of-archive.tar.gz /path/to/directory-or-file -c: Create an archive. -z: Compress the ...

  10. unittest----常用属性详解(框架属性详解)

    很久没有写关于测试的随笔了,最近有空学习.整理一下关于unittest框架的知识. unittest单元测试框架,不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行. unittest ...