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

Spring认证中国教育管理中心-Apache Geode 的 Spring 数据教程十八

  1. 应用 Apache Geode API
    一旦配置了 Apache Geode Cache 和 Regions,它们就能够被注入并在应用程序对象中应用。本章形容了与 Spring 的事务管理性能和 DAO 异样层次结构的集成。本章还介绍了对 Apache Geode 治理对象的依赖注入的反对。

7.1.Gemfire模板
与 Spring 提供的许多其余高级形象一样,Spring Data for Apache Geode 提供了一个模板 来简化 Apache Geode 数据拜访操作。该类提供了几种蕴含常见 Region 操作的办法,但也提供了针对本机 Apache Geode API执行代码的性能,而无需应用GemfireCallback.

模板类须要一个 Apache Geode Region,一旦配置,就是线程平安的,并且能够跨多个应用程序类重用:

<bean id="gemfireTemplate" class="org.springframework.data.gemfire.GemfireTemplate" p:region-ref="SomeRegion"/>
配置模板后,开发人员能够将其与GemfireCallbackApache Geode一起应用,Region而无需解决查看异样、线程或资源管理问题:

template.execute(new GemfireCallback<Iterable<String>>() {

public Iterable<String> doInGemfire(Region region)        throws GemFireCheckedException, GemFireException {    Region<String, String> localRegion = (Region<String, String>) region;    localRegion.put("1", "one");    localRegion.put("3", "three");    return localRegion.query("length < 5");}

});
为了充分发挥Apache Geode查询语言的威力,开发者能够应用findandfindUnique 办法,与办法相比query,能够跨多个Region执行查问,执行投影等。

find当查问抉择多个我的项目(通过SelectResults)时应该应用该办法,而后者, findUnique顾名思义,当只返回一个对象时。

7.2.异样翻译
应用新的数据拜访技术不仅须要适应新的 API,还须要解决特定于该技术的异样。

为了适应异样解决的状况,Spring 框架提供了一个技术无关且统一的 异样层次结构 ,将应用程序从专有的、通常是“查看的”异样形象为一组集中的运行时异样。

正如Spring Framework 的文档中所提到的,通过定义bean 应用正文和 AOP , 异样转换能够通明地利用于您的数据拜访对象 (DAO) 。应用 Apache Geode 时,只有申明了雷同的异样转换性能,就会启用雷同的异样转换性能,例如应用 a 或申明,它充当异样转换器并由 Spring 基础设施自动检测并相应地应用。@
RepositoryPersistenceExceptionTranslationPostProcessorCacheFactoryBean<gfe:cache/><gfe:client-cache>

7.3.本地、缓存事务管理
Spring 框架最风行的个性之一是 事务管理。

如果你不相熟Spring的事务形象那么咱们强烈建议您 浏览 无关Spring的事务管理的基础设施,因为它提供了一个统一的编程模型,跨多个API通明地工作,并且能够通过编程形式或申明(最风行的抉择)配置。

对于 Apache Geode,Apache Geode 的 Spring Data 提供了一个专用的每个缓存
PlatformTransactionManager,一旦申明,就容许通过 Spring 原子地执行 Region 操作:

应用 XML 启用事务管理

<gfe:transaction-manager id="txManager" cache-ref="myCache"/>
下面的例子中,能够通过打消甚至进一步简化cache-ref,如果在Apache的Geode缓存下默认名称定义的属性,gemfireCache。与其余 Spring Data for Apache Geode 命名空间元素一样,如果未配置缓存 bean 名称,则将应用上述命名约定。此外,如果未明确指定,事务管理器名称为“gemfireTransactionManager”。

目前,Apache Geode 反对具备读提交隔离的乐观事务。此外,为了保障这种隔离,开发人员应防止进行手动批改缓存中存在的值的就地更改。为了避免这种状况产生,事务管理器默认将缓存配置为在读取时应用复制语义,这意味着每次执行读取时都会创立理论值的克隆。如果须要,能够通过copyOnRead属性禁用此行为。

因为在启用读取时复制时会复制给定键的值,因而您必须随后调用 Region.put(key, value)inorder 以事务形式更新值。

无关底层 Geode 事务管理器的语义和行为的更多信息,请参阅 Geode CacheTransactionManager Javadoc 。

公共接口CacheTransactionManager
CacheTransactionManager 接口容许应用程序在每个Cache根底上治理事务 。

GemFire 事务的生命周期从开始操作开始。生命周期以提交或回滚操作完结。在开始和提交/回滚之间通常是 Region操作。通常,那些创立、销毁、生效或更新的操作 Region.Entry被认为是事务性的,即它们批改事务状态。

一个 GemFire 事务可能波及对多个区域的操作,每个区域可能具备不同的属性。

在本地 VM 中调用 GemFire 事务及其操作时,依据每个参加区域的属性,在提交时将生成的事务状态散发到其余 VM。

一个事务最多只能有一个与之关联的线程,相同,一个线程在任何给定工夫只能对一个事务进行操作。子线程不会继承现有事务。

以下每个办法都在以后线程上运行。CacheClosedException如果 Cache 敞开,则所有办法都会抛出 。

GemFire Transactions 目前只反对 Read Committed 隔离。此外,它们是乐观事务,因为写锁定和抵触查看是作为提交操作的一部分执行的。

为了保障读已提交隔离,防止进行“就地”更改,因为此类更改将被其余事务“看到”并毁坏读已提交隔离保障。例如

CacheTransactionManager txMgr = cache.getCacheTransactionManager();
txMgr.begin();
StringBuffer s = (StringBuffer) r.get("stringBuf");
s.append("提交前看到的更改。未提交读取!");
r.put("stringBuf", s);
txMgr.commit();

为了帮忙创立正本,提供了“读取时复制”Cache属性和 CopyHelper.copy(T)办法。以下是应用该CopyHelper.copy办法的 Read Committed 平安示例。

CacheTransactionManager txMgr = cache.getCacheTransactionManager();
txMgr.begin();
Object o = r.get("stringBuf");
StringBuffer s = (StringBuffer) CopyHelper.copy(o);
s.append("提交前未见更改。已提交读取。");
r.put("stringBuf", s);
txMgr.commit();

须要留神的是,创立正本会对性能和内存耗费产生负面影响。

反对分区区域、分布式无确认和分布式确认区域(参见 AttributesFactory范畴)。对于这两个范畴,强制执行统一的配置(每个 VM)。

全局区域、客户端区域(参见 org.apache.geode.cache.client 包)和长久区域(参见 参考资料DiskWriteAttributes)不反对事务。

当 PartitionedRegions 参加到一个事务中时,事务中的所有数据必须独特位于一个数据节点上。无关在分区区域中应用事务的详细信息,请参阅 GemFire 开发人员指南。

7.4.全局,JTA 事务管理
Apache Geode 也能够参加基于 JTA 的全局事务,例如由 Java EE 应用服务器(例如 WebSphere 应用服务器(WAS))应用容器治理事务(CMT)和其余 JTA 资源管理的事务。

然而,与许多其余 JTA“兼容”资源(例如,像 ActiveMQ 这样的 JMS 音讯代理)不同,Apache Geode不是 XA 兼容资源。因而,Apache Geode 必须被定位为JTA 事务(筹备阶段)中的“最初一个资源”,因为它没有实现两阶段提交协定,或者更确切地说,它不解决分布式事务。

许多反对 CMT 的托管环境在基于 JTA 的事务中保护对“最初资源”、非 XA 兼容资源的反对,只管 JTA 标准实际上并不需要它。无关不合乎 XA 的“最初资源”的含意的更多信息能够在 Red Hat 的文档中找到。事实上,Red Hat 的 JBoss 我的项目Narayana就是这样一种 LGPL 开源实现。Narayana 将此称为“最初资源提交优化”(LRCO)。能够在此处找到更多详细信息。

然而,无论您是在具备反对“最初资源”的开源 JTA 事务管理实现的独立环境中应用 Apache Geode ,还是在托管环境(例如 Java EE AS,如 WAS)中应用 Apache Geode,Apache Geode 的 Spring Data 都能满足您的需要。

您必须实现一系列步骤能力在波及 1 个以上事务资源的 JTA 事务中正确应用 Apache Geode 作为“最初一个资源”。此外,在这种安顿中只能有 1 个非 XA 兼容资源(例如 Apache Geode)。

1) 首先,您必须在此处实现 Apache Geode 文档中的步骤 1-4 。

下面的 #1 独立于您的 Spring [Boot] 和/或 [Data for Apache Geode] 应用程序,并且必须胜利实现。

2) 参考 Apache Geode文档中的第 5 步,Spring Data for Apache Geode's Annotation support 将尝试 在应用正文时为您设置GemFireCache,copyOnRead属性@
EnableGemFireAsLastResource。

然而,如果 SDG 在这方面的主动配置不胜利,那么您必须copy-on-read 在<gfe:cache>或<gfe:client-cache>XML 元素中显式设置该属性或将JavaConfigcopyOnRead中的CacheFactoryBean类的属性设置为true。例如:

ClientCache XML:

应用 XML(客户端)设置读取时复制

<gfe:client-cache ... copy-on-read="true"/>
ClientCache Java配置:

应用 JavaConfig(客户端)设置 copyOnRead

@Bean
ClientCacheFactoryBean gemfireCache() {

ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();

gemfireCache.setCopyOnRead(true);

return gemfireCache;
}
对等CacheXML:

应用 XML(服务器)设置读取时复制

<gfe:cache ... copy-on-read="true"/>
对等Cache JavaConfig:

应用 JavaConfig(服务器)设置 copyOnRead

@Bean
CacheFactoryBean gemfireCache() {

CacheFactoryBean gemfireCache = new CacheFactoryBean();

gemfireCache.setCopyOnRead(true);

return gemfireCache;
}
显式设置copy-on-read属性或copyOnRead属性实际上是没有必要的。启用事务管理须要在读取时进行复制。

3) 此时,您能够跳过Apache Geode文档中的步骤 6-8 ,让Spring Data Geode施展其魔力。您须要做的就是@Configuration应用 Spring Data for Apache Geode 的新 @
EnableGemFireAsLastResource注解来注解您的 Spring类,并且 Spring 的 事务管理基础设施和 Spring Data for Apache Geode 的 @EnableGemFireAsLastResource注解配置的组合就能够解决问题。

配置看起来像这样......

@Configuration
@EnableGemFireAsLastResource
@EnableTransactionManagement(order = 1)
class GeodeConfiguration {
...
}
惟一的要求是……

3.1)@
EnableGemFireAsLastResource注解必须在指定@ConfigurationSpring@EnableTransactionManagement注解的同一个Spring类上申明。

3.2)正文的order属性@
EnableTransactionManagement必须显式设置为整数值,不是Integer.MAX_VALUE或Integer.MIN_VALUE(默认为Integer.MAX_VALUE)。

当然,心愿你晓得JtaTransactionManager 在应用 JTA 事务时你还须要配置 Spring 的。

@Bean
public JtaTransactionManager transactionManager(UserTransaction userTransaction) {

JtaTransactionManager transactionManager = new JtaTransactionManager();

transactionManager.setUserTransaction(userTransaction);

return transactionManager;
}
在节中的配置本地,缓存事务管理并没有实用于此。Spring Data for Apache Geode 的应用GemfireTransactionManager实用于“仅限本地”、缓存事务, 而不是“全局”、JTA 事务。因而,在这种状况下不配置 SDG GemfireTransactionManager。您JtaTransactionManager如上所示配置 Spring 。

无关将Spring 的事务管理与 JTA 联合应用的更多详细信息,请参见此处。

实际上,Spring Data for Apache Geode 的@
EnableGemFireAsLastResource注解导入了蕴含 2 个 Aspect bean 定义的配置,这些定义在事务操作期间的适当点解决 Apache Geodeo.a.g.ra.GFConnectionFactory.getConnection() 和o.a.g.ra.GFConnection.close()操作。

具体来说,正确的事件程序如下:

jtaTransation.begin()

GFConnectionFactory.getConnection()

调用应用程序的@Transactional服务办法

无论是jtaTransaction.commit()或jtaTransaction.rollback()

最初, GFConnection.close()

这与您作为应用程序开发人员在必须本人应用 JTA API + Apache Geode API 时手动编码的形式统一,如 Apache Geode示例 所示。

值得庆幸的是,Spring 为您实现了沉重的工作,在利用适当的配置(如上所示)后,您须要做的就是:

将服务办法申明为@Transactional

@Service
class MyTransactionalService {

@Transactional
public <Return-Type> someTransactionalServiceMethod() {

// perform business logic interacting with and accessing multiple JTA resources atomically

}

...
}

PlatformTransactionManager一旦 @Transactional您的应用程序进入边界(即MyTransactionService.someTransactionalServiceMethod() 调用时),下面的#1 和#4 就会由基于Spring 的JTA 适当地解决。

2 和 #3 由 Spring Data 解决,用于启用@

EnableGemFireAsLastResource正文的Apache Geode 的新方面。

3 当然是你的应用程序的责任。

事实上,通过配置适当的日志记录,您将看到正确的事件序列......

事务日志输入

2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Getting transaction for [example.app.service.MessageService.send]

2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionAcquiringAspect - Acquiring {data-store-name} Connection
from {data-store-name} JCA ResourceAdapter registered at [gfe/jca]

2017-Jun-22 11:11:37 TRACE MessageService - PRODUCER [ Message :
[{ @type = example.app.domain.Message, id= MSG0000000000, message = SENT }],
JSON : [{"id":"MSG0000000000","message":"SENT"}] ]

2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Completing transaction for [example.app.service.MessageService.send]

2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionClosingAspect - Closed {data-store-name} Connection @ [Reference [...]]