原题目:Spring认证中国教育管理中心-Apache Geode 的 Spring 数据教程二十三(Spring中国教育管理中心)

Apache Geode 的 Spring 数据教程二十三

  1. Apache Geode 存储库的 Spring 数据
    Spring Data for Apache Geode 反对应用 Spring Data Repository 形象来轻松地将实体长久化到 Apache Geode 中,同时执行查问。此处提供了对存储库编程模型的个别介绍。

10.1.Spring XML 配置
要疏导 Spring Data Repositories,请应用<repositories/>Spring Data for Apache Geode Data 命名空间中的元素,如以下示例所示:

示例 7. 应用 XML 为 Apache Geode 存储库启动 Spring 数据

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:gfe-data="https://www.springframework.org/schema/data/geode"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdhttps://www.springframework.org/schema/data/geode https://www.springframework.org/schema/data/geode/spring-data-geode.xsd

">

<gfe-data:repositories base-package="com.example.acme.repository"/>

</beans>
后面的配置片段在配置的根本包下查找接口,并为由SimpleGemFireRepository.

除非您将应用程序域类正确映射到配置的区域,否则疏导过程将失败。

10.2.基于 Spring Java 的配置
或者,许多开发人员更喜爱应用 Spring 的基于 Java 的容器配置。

应用这种办法,您能够应用 SDG@EnableGemfireRepositories 正文疏导 Spring Data Repositories ,如以下示例所示:

示例 8. 应用 Apache Geode 存储库疏导 Spring 数据 @EnableGemfireRepositories

@SpringBootApplication
@EnableGemfireRepositories(basePackages = "com.example.acme.repository")
class SpringDataApplication {
...
}
而不是应用basePackages属性,你可能更违心应用类型平安的basePackageClasses属性来代替。将basePackageClasses让你指定只指定您的利用程序库的接口类型中的一种蕴含了所有的利用程序库类的包。思考在每个包中创立一个非凡的无操作标记类或接口,除了标识此属性援用的应用程序存储库的地位外,没有其余用处。

除了basePackages and basePackageClasses属性,如 Spring 的 @ComponentScan注解,@EnableGemfireRepositories注解提供了蕴含和排除过滤器,基于 Spring 的 ComponentScan.Filter类型。您能够应用该filterType属性按不同方面进行过滤,例如应用程序 Repository 类型是否应用特定的注解进行注解或扩大特定的类类型等等。无关 更多详细信息,请参阅 FilterTypeJavadoc。

该@EnableGemfireRepositories注解也让你指定一个名为OQL查问,这驻留在一个Java的地位Properties文件,通过应用namedQueriesLocation属性。属性名称必须与 Repository 查询方法的名称匹配,并且属性值是调用 Repository 查询方法时要执行的 OQL 查问。

如果您的应用程序须要一个或多个自定义存储库实现,
repositoryImplementationPostfix则能够将该属性设置为代替值(默认为Impl)。此性能通常用于扩大 Spring Data Repository 基础架构以实现数据存储未提供的性能(例如 SDG)。

Apache Geode 须要自定义存储库实现的一个示例是执行连贯时。SDG 存储库不反对联接。对于 Apache Geode PARTITIONRegion,连贯必须在并置的PARTITIONRegion上执行,因为 Apache Geode 不反对“分布式”连贯。此外,Equi-Join OQL 查问必须在 Apache Geode 函数内执行。无关 Apache Geode Equi-Join Queries 的更多详细信息,请参见此处。

SDG 存储库基础设施扩大的许多其余方面也能够进行定制。无关@EnableGemfireRepositories 所有配置设置的更多详细信息,请参阅 Javadoc。

10.3.执行 OQL 查问
Spring Data for Apache Geode Repositories 反对定义查询方法,以便针对托管实体映射到的区域轻松执行 Apache Geode OQL 查问,如下例所示:

示例 9. 示例存储库

@Region("People")
public class Person { … }
public interface PersonRepository extends CrudRepository<Person, Long> {

Person findByEmailAddress(String emailAddress);

Collection<Person> findByFirstname(String firstname);

@Query("SELECT * FROM /People p WHERE p.firstname = $1")
Collection<Person> findByFirstnameAnnotated(String firstname);

@Query("SELECT * FROM /People p WHERE p.firstname IN SET $1")
Collection<Person> findByFirstnamesAnnotated(Collection<String> firstnames);
}
后面示例中列出的第一个查询方法导致派生以下 OQL 查问: SELECT x FROM /People x WHERE x.emailAddress = $1. 第二个查询方法的工作形式雷同,只是它返回找到的所有实体,而第一个查询方法冀望找到单个后果。

如果反对的关键字不足以申明和表白您的 OQL 查问,或者办法名称变得过于简短,那么您能够应用@Query如第三和第四种办法所示的正文查询方法。

下表提供了可在查询方法中应用的受反对关键字的简要示例:

Apache Geode 的 Spring 数据教程二十三
10.4.应用注解的 OQL 查问扩大
许多查询语言,例如 Apache Geode 的 OQL(对象查询语言),具备 Spring Data Commons 的 Repository 基础架构不间接反对的扩大。

Spring Data Commons 的 Repository 基础设施指标之一是充当最低公分母,以放弃对当今利用程序开发中可用和应用的最宽泛数据存储的反对和可移植性。从技术上讲,这意味着开发人员能够通过重用现有的特定于应用程序的 Repository 接口(一种不便且弱小的形象),在其应用程序中拜访 Spring Data Commons 反对的多个不同数据存储。

为了反对 Apache Geode 的 OQL 查询语言扩大并放弃跨不同数据存储的可移植性,Spring Data for Apache Geode 通过应用 Java 正文增加了对 OQL 查问扩大的反对。这些注解会被其余没有相似查询语言个性的 Spring Data Repository 实现(例如 Spring Data JPA 或 Spring Data Redis)疏忽。

例如,许多数据存储很可能没有实现 Apache Geode 的 OQLIMPORT关键字。施行IMPORT 作为正文(即,@Import),而不是作为查询方法签名的一部分(具体而言,该办法“姓名”)不与所述解析基础设施评估查询方法名结构另一个数据存储器语言适当的查问时烦扰。

目前,Spring Data for Apache Geode 反对的 Apache Geode OQL 查询语言扩大集包含:

例如,假如您有一个Customers应用程序域类和相应的 Apache Geode Region 以及一个按姓氏CustomerRepository查找的查询方法Customers,如下所示:

示例 10. 示例客户存储库

package ...;

import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.annotation.Region;
...

@Region("Customers")
public class Customer ... {

@Id
private Long id;

...
}
package ...;

import org.springframework.data.gemfire.repository.GemfireRepository;
...

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

@Trace
@Limit(10)
@Hint("LastNameIdx")
@Import("org.example.app.domain.Customer")
List<Customer> findByLastName(String lastName);

...
}
Apache Geode 的 Spring 数据教程二十三
后面的示例产生以下 OQL 查问:

<TRACE> <HINT 'LastNameIdx'> IMPORT org.example.app.domain.Customer; SELECT * FROM /Customers x WHERE x.lastName = $1 LIMIT 10

当 OQL 正文扩大与@Query正文联合应用时,Apache Geode 的 Repository 扩大的 Spring Data 小心不要创立抵触的申明。

再举一个例子,假如你@Query在你的 中定义了一个原始的带正文的查询方法CustomerRepository,如下所示:

示例 11. CustomerRepository

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

@Trace
@Limit(10)
@Hint("CustomerIdx")
@Import("org.example.app.domain.Customer")
@Query("<TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers c WHERE c.reputation > $1 ORDER BY c.reputation DESC LIMIT 5")
List<Customer> findDistinctCustomersByReputationGreaterThanOrderByReputationDesc(Integer reputation);

}
上述查询方法产生以下 OQL 查问:

IMPORT org.example.app.domain.Customer; <TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers x WHERE x.reputation > $1 ORDER BY c.reputation DESC LIMIT 5

该@Limit(10)正文不会笼罩LIMIT在原始查问中明确定义。此外,@Hint("CustomerIdx")正文不会笼罩HINT原始查问中明确定义的。最初,@Trace正文是多余的,没有额定的作用。

ReputationIdx思考到可能对其名誉具备雷同价值的客户数量,该指数可能不是最理智的指数,这会升高该指数的有效性。请明智地抉择索引和其余优化,因为因为保护索引的开销,不正确或抉择不当的索引会对您的性能产生相同的影响。该ReputationIdx只用来为例子的目标。

10.5.查问后处理
因为应用了 Spring Data Repository 形象,用于定义数据存储特定查问(例如 OQL)的查询方法约定变得简略不便。然而,有时仍心愿查看甚至可能批改从 Repository 查询方法生成的查问。

从 2.0.x 开始,Apache Geode 的 Spring Data 蕴含
o.s.d.gemfire.repository.query.QueryPostProcessor性能接口。接口的定义涣散如下:

示例 12. QueryPostProcessor

package org.springframework.data.gemfire.repository.query;

import org.springframework.core.Ordered;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.QueryMethod;
import ...;

@FunctionalInterface
interface QueryPostProcessor<T extends Repository, QUERY> extends Ordered {

QUERY postProcess(QueryMethod queryMethod, QUERY query, Object... arguments);

}
提供了额定的默认办法,让您能够组合QueryPostProcessor相似于
java.util.function.Function.andThen(:Function) 和java.util.function.Function.compose(:Function) 工作形式的实例。

此外,该QueryPostProcessor接口实现了该
org.springframework.core.Ordered接口,当QueryPostProcessors在 Spring 容器中申明和注册多个并用于为一组生成的查询方法查问创立解决管道时,该接口 很有用。

最初,QueryPostProcessor承受别离对应于类型参数T和的类型参数QUERY。类型T扩大了 Spring Data Commons 标记接口,
org.springframework.data.repository.Repository. 咱们将在本节前面进一步探讨这一点。QUERYApache Geode 案例的 Spring Data 中的所有类型参数参数都是 java.lang.String.

将查问定义为 type 很有用QUERY,因为这个QueryPostProcessor接口能够移植到 Spring Data Commons,因而必须解决不同数据存储(例如 JPA、MongoDB 或 Redis)的所有模式的查问。

您能够实现此接口,以通过调用该Repository办法时从利用程序接口办法生成的查问接管回调 。

例如,您可能心愿记录来自所有应用程序存储库接口定义的所有查问。您能够通过应用以下QueryPostProcessor实现来做到这一点:

示例 13. LoggingQueryPostProcessor

package example;

import ...;

class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

private Logger logger = Logger.getLogger("someLoggerName");

@Override
public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

  String message = String.format("Executing query [%s] with arguments [%s]", query, Arrays.toString(arguments));  this.logger.info(message);

}
}
将LoggingQueryPostProcessor已键入了Spring数据
org.springframework.data.repository.Repository 标记接口,并且因而,记录所有利用程序库接口查询方法生成的查问。

您能够将此日志记录的范畴限度为仅来自某些类型的应用程序存储库接口的查问,例如 a CustomerRepository,如以下示例所示:

示例 14. CustomerRepository

interface CustomerRepository extends CrudRepository<Customer, Long> {

Customer findByAccountNumber(String accountNumber);

List<Customer> findByLastNameLike(String lastName);

}
而后,您能够LoggingQueryPostProcessor专门在 中键入CustomerRepository,如下所示:

示例 15.
CustomerLoggingQueryPostProcessor

class LoggingQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> { .. }
因而,只会记录CustomerRepository界面中定义的查问,例如findByAccountNumber。

您可能心愿为QueryPostProcessor存储库查询方法定义的特定查问创立一个。例如,假如您心愿将
CustomerRepository.findByLastNameLike(:String)查询方法生成的 OQL 查问限度为仅返回五个后果,并按升序对CustomersbyfirstName进行排序。为此,您能够定义一个 custom QueryPostProcessor,如以下示例所示:

示例 16.
OrderedLimitedCustomerByLastNameQueryPostProcessor

class OrderedLimitedCustomerByLastNameQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

private final int limit;

public OrderedLimitedCustomerByLastNameQueryPostProcessor(int limit) {

this.limit = limit;

}

@Override
public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

return "findByLastNameLike".equals(queryMethod.getName())  ? query.trim()      .replace("SELECT", "SELECT DISTINCT")      .concat(" ORDER BY firstName ASC")      .concat(String.format(" LIMIT %d", this.limit))  : query;

}
}
尽管后面的示例无效,但您能够通过应用 Spring Data for Apache Geode 提供的 Spring Data Repository 约定来实现雷同的成果。例如,雷同的查问能够定义如下:

示例 17. CustomerRepository 应用约定

interface CustomerRepository extends CrudRepository<Customer, Long> {

@Limit(5)
List<Customer> findDistinctByLastNameLikeOrderByFirstNameDesc(String lastName);

}
然而,如果您无奈控制应用程序CustomerRepository接口定义,那么QueryPostProcessor(即
OrderedLimitedCustomerByLastNameQueryPostProcessor)很不便。

如果要确保LoggingQueryPostProcessor始终在其余利用程序定义的 QueryPostProcessors可能已在 Spring 中申明和注册的 bean 之后ApplicationContext,则能够order通过笼罩该o.s.core.Ordered.getOrder()办法来设置该属性,如下例所示:

示例 18. 定义order属性

class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

@Override
int getOrder() {

return 1;

}
}

class CustomerQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

@Override
int getOrder() {

return 0;

}
}
这确保您始终能够QueryPostProcessors 在LoggingQueryPostProcessor记录查问之前看到其余利用的前期解决的成果。

您能够依据须要QueryPostProcessors在 Spring 中定义ApplicationContext任意数量,并以任意程序将它们利用于所有或特定应用程序存储库接口,并通过应用提供的postProcess(..)办法回调参数来尽可能细化。