DATAGEODE-152 - Polish.
Resolve gh-27.
This commit is contained in:
@@ -79,18 +79,19 @@ about _Spring's Transaction Management_ infrastructure as it offers a consistent
|
|||||||
transparently across multiple APIs and can be configured either programmatically or declaratively
|
transparently across multiple APIs and can be configured either programmatically or declaratively
|
||||||
(the most popular choice).
|
(the most popular choice).
|
||||||
|
|
||||||
For {data-store-name}, {sdg-name} provides a dedicated, per-cache, `PlatformTransactionManager` that,
|
For {data-store-name}, {sdg-name} provides a dedicated, per-cache, `PlatformTransactionManager` that, once declared,
|
||||||
once declared, allows Region operations to be executed atomically through Spring:
|
allows Region operations to be executed atomically through Spring:
|
||||||
|
|
||||||
|
.Enable Transaction Management using XML
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
<gfe:transaction-manager id="txManager" cache-ref="myCache"/>
|
<gfe:transaction-manager id="txManager" cache-ref="myCache"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
NOTE: The example above can be simplified even further by eliminating the `cache-ref` attribute if the {data-store-name} cache
|
NOTE: The example above can be simplified even further by eliminating the `cache-ref` attribute if the {data-store-name}
|
||||||
is defined under the default name, `gemfireCache`. As with the other {sdg-name} namespace elements,
|
cache is defined under the default name, `gemfireCache`. As with the other {sdg-name} namespace elements, if the cache
|
||||||
if the cache bean name is not configured, the aforementioned naming convention will be used.
|
bean name is not configured, the aforementioned naming convention will be used. Additionally, the transaction manager
|
||||||
Additionally, the transaction manager name is "`gemfireTransactionManager`" if not explicitly specified.
|
name is "`gemfireTransactionManager`" if not explicitly specified.
|
||||||
|
|
||||||
Currently, {data-store-name} supports optimistic transactions with *read committed* isolation. Furthermore, to guarantee
|
Currently, {data-store-name} supports optimistic transactions with *read committed* isolation. Furthermore, to guarantee
|
||||||
this isolation, developers should avoid making *in-place* changes that manually modify values present in the cache.
|
this isolation, developers should avoid making *in-place* changes that manually modify values present in the cache.
|
||||||
@@ -98,6 +99,9 @@ To prevent this from happening, the transaction manager configures the cache to
|
|||||||
meaning a clone of the actual value is created each time a read is performed. This behavior can be disabled if needed
|
meaning a clone of the actual value is created each time a read is performed. This behavior can be disabled if needed
|
||||||
through the `copyOnRead` property.
|
through the `copyOnRead` property.
|
||||||
|
|
||||||
|
Since a copy of the value for a given key is made when *copy on read* is enabled, you must subsequently call
|
||||||
|
`Region.put(key, value)` inorder for the value to be updated, transactionally.
|
||||||
|
|
||||||
For more information on the semantics and behavior of the underlying Geode transaction manager, please refer to the Geode
|
For more information on the semantics and behavior of the underlying Geode transaction manager, please refer to the Geode
|
||||||
{x-data-store-javadoc}/org/apache/geode/cache/CacheTransactionManager.html[CacheTransactionManager Javadoc]
|
{x-data-store-javadoc}/org/apache/geode/cache/CacheTransactionManager.html[CacheTransactionManager Javadoc]
|
||||||
as well as the {x-data-store-docs}/developing/transactions/chapter_overview.html[documentation].
|
as well as the {x-data-store-docs}/developing/transactions/chapter_overview.html[documentation].
|
||||||
@@ -105,76 +109,54 @@ as well as the {x-data-store-docs}/developing/transactions/chapter_overview.html
|
|||||||
[[apis:global-transaction-management]]
|
[[apis:global-transaction-management]]
|
||||||
== Global, JTA Transaction Management
|
== Global, JTA Transaction Management
|
||||||
|
|
||||||
It is also possible for {data-store-name} to participate in a Global, JTA based transaction, such as a transaction managed
|
It is also possible for {data-store-name} to participate in Global, JTA-based transactions, such as a transaction
|
||||||
by an Java EE Application Server (e.g. WebSphere Application Server, a.k.a. WAS) using Container Managed Transactions
|
managed by an Java EE Application Server (e.g. WebSphere Application Server (WAS)) using Container Managed Transactions
|
||||||
(CMT) along with other JTA resources.
|
(CMT) along with other JTA resources.
|
||||||
|
|
||||||
However, unlike many other JTA "compliant" resources (e.g. JMS Message Brokers like ActiveMQ), {data-store-name} is *not*
|
However, unlike many other JTA "compliant" resources (e.g. JMS Message Brokers like ActiveMQ), {data-store-name} is *not*
|
||||||
an XA compliant resource. Therefore, {data-store-name} must be positioned as the "_Last Resource_" in a JTA transaction
|
an XA compliant resource. Therefore, {data-store-name} must be positioned as the "_Last Resource_" in a JTA transaction
|
||||||
(_prepare phase_) since it does not implement the 2-phase commit protocol, or rather does not handle
|
(_prepare phase_) since it does not implement the 2-phase commit protocol, or rather does not handle distributed
|
||||||
distributed transactions.
|
transactions.
|
||||||
|
|
||||||
Many managed environments with CMT maintain support for "_Last Resource_", non-XA compliant resources in JTA transactions
|
Many managed environments capable of CMT maintain support for "_Last Resource_", non-XA compliant resources in JTA-based
|
||||||
though it is not actually required in the JTA spec. More information on what a non-XA compliant, "_Last Resource_" means
|
transactions, though it is not actually required in the JTA spec. More information on what a non-XA compliant,
|
||||||
can be found in Red Hat's https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/5/html/Administration_And_Configuration_Guide/lrco-overview.html[documentation].
|
"_Last Resource_" means can be found in Red Hat's https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/5/html/Administration_And_Configuration_Guide/lrco-overview.html[documentation].
|
||||||
In fact, Red Hat's JBoss project, https://narayana.io/[Narayana] is one such LGPL Open Source implementation. _Narayana_
|
In fact, Red Hat's JBoss project, https://narayana.io/[Narayana] is one such LGPL Open Source implementation. _Narayana_
|
||||||
refers to this as "_Last Resource Commit Optimization_" (LRCO). More details can be found
|
refers to this as "_Last Resource Commit Optimization_" (LRCO). More details can be found https://narayana.io//docs/project/index.html#d0e1859[here].
|
||||||
https://narayana.io//docs/project/index.html#d0e1859[here].
|
|
||||||
|
|
||||||
However, whether you are using {data-store-name} in a standalone environment with an Open Source JTA Transaction Management
|
However, whether you are using {data-store-name} in a standalone environment with an Open Source JTA Transaction
|
||||||
implementation that supports "_Last Resource_", or a managed environment (e.g. Java EE AS such as WAS),
|
Management implementation that supports "_Last Resource_", or a managed environment (e.g. Java EE AS such as WAS),
|
||||||
_Spring Data Geode_ has you covered.
|
{sdg-name} has you covered.
|
||||||
|
|
||||||
There are a series of steps you must complete to properly use {data-store-name} as a "_Last Resource_" in a JTA transaction
|
There are a series of steps you must complete to properly use {data-store-name} as a "_Last Resource_" in a JTA
|
||||||
involving more than 1 transactional resource. Additionally, there can only be 1 non-XA compliant resource
|
transaction involving more than 1 transactional resource. Additionally, there can only be 1 non-XA compliant resource
|
||||||
(e.g. {data-store-name}) in such an arrangement.
|
(e.g. {data-store-name}) in such an arrangement.
|
||||||
|
|
||||||
1) First, you must complete Steps 1-4 in {data-store-name}'s documentation
|
1) First, you must complete Steps 1-4 in {data-store-name}'s documentation
|
||||||
https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[here].
|
{apache-geode-docs}/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[here].
|
||||||
|
|
||||||
NOTE: #1 above is independent of your Spring [Boot] and/or [Data for {data-store-name}] application
|
NOTE: #1 above is independent of your Spring [Boot] and/or [Data for {data-store-name}] application and must be
|
||||||
and must be completed successfully.
|
completed successfully.
|
||||||
|
|
||||||
2) Referring to Step 5 in {data-store-name}'s https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[documentation],
|
2) Referring to Step 5 in {data-store-name}'s {apache-geode-docs}/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[documentation],
|
||||||
{sdg-name}'s Annotation support will attempt to set the `GemFireCache`, {x-data-store-javadoc}/org/apache/geode/cache/GemFireCache.html#setCopyOnRead-boolean-[`copyOnRead`]
|
{sdg-name}'s Annotation support will attempt to set the `GemFireCache`, {x-data-store-javadoc}/org/apache/geode/cache/GemFireCache.html#setCopyOnRead-boolean-[`copyOnRead`]
|
||||||
property for you when using the `@EnableGemFireAsLastResource` annotation.
|
property for you when using the `@EnableGemFireAsLastResource` annotation.
|
||||||
|
|
||||||
However, if SDG's auto-configuration is unsuccessful then you must explicitly set the `copy-on-read` attribute on the
|
However, if SDG's auto-configuration is unsuccessful in this regard, then you must explicitly set the `copy-on-read`
|
||||||
`<gfe:cache>` or `<gfe:client-cache>` element in XML or the `copyOnRead` property of the SDG `CacheFactoryBean` class
|
attribute in the `<gfe:cache>` or `<gfe:client-cache>` XML element or set the `copyOnRead` property of
|
||||||
in JavaConfig to *true*. For example...
|
the `CacheFactoryBean` class in JavaConfig to *true*. For example:
|
||||||
|
|
||||||
Peer Cache XML:
|
`ClientCache` XML:
|
||||||
|
|
||||||
[source,xml]
|
|
||||||
----
|
|
||||||
<gfe:cache ... copy-on-read="true"/>
|
|
||||||
----
|
|
||||||
|
|
||||||
Peer Cache JavaConfig:
|
|
||||||
|
|
||||||
[source,java]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
CacheFactoryBean gemfireCache() {
|
|
||||||
|
|
||||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
|
||||||
|
|
||||||
gemfireCache.setClose(true);
|
|
||||||
gemfireCache.setCopyOnRead(true);
|
|
||||||
|
|
||||||
return gemfireCache;
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
Client Cache XML:
|
|
||||||
|
|
||||||
|
.Set copy-on-read using XML (client)
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
<gfe:client-cache ... copy-on-read="true"/>
|
<gfe:client-cache ... copy-on-read="true"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
Client Cache JavaConfig:
|
`ClientCache` _JavaConfig_:
|
||||||
|
|
||||||
|
.Set copyOnRead using JavaConfig (client)
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
@@ -182,21 +164,44 @@ ClientCacheFactoryBean gemfireCache() {
|
|||||||
|
|
||||||
ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();
|
ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();
|
||||||
|
|
||||||
gemfireCache.setClose(true);
|
|
||||||
gemfireCache.setCopyOnRead(true);
|
gemfireCache.setCopyOnRead(true);
|
||||||
|
|
||||||
return gemfireCache;
|
return gemfireCache;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
NOTE: explicitly setting the `copy-on-read` attribute or optionally the `copyOnRead` property
|
Peer `Cache` XML:
|
||||||
really should not be necessary.
|
|
||||||
|
|
||||||
3) At this point, you *skip* Steps 6-8 in {data-store-name}'s https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[documentation]
|
.Set copy-on-read using XML (server)
|
||||||
and let _Spring Data Geode_ work its magic. All you need do is annotate your Spring `@Configuration` class
|
[source,xml]
|
||||||
|
----
|
||||||
|
<gfe:cache ... copy-on-read="true"/>
|
||||||
|
----
|
||||||
|
|
||||||
|
Peer `Cache` _JavaConfig_:
|
||||||
|
|
||||||
|
.Set copyOnRead using JavaConfig (server)
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
CacheFactoryBean gemfireCache() {
|
||||||
|
|
||||||
|
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||||
|
|
||||||
|
gemfireCache.setCopyOnRead(true);
|
||||||
|
|
||||||
|
return gemfireCache;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
NOTE: Explicitly setting the `copy-on-read` attribute or the `copyOnRead` property is really not necessary. Enabling
|
||||||
|
transaction management takes case of copying on reads.
|
||||||
|
|
||||||
|
3) At this point, you *skip* Steps 6-8 in {data-store-name}'s {apache-geode-docs}/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[documentation]
|
||||||
|
and let _Spring Data Geode_ work its magic. All you need to do is annotate your Spring `@Configuration` class
|
||||||
with {sdg-name}'s *new* `@EnableGemFireAsLastResource` annotation and a combination of Spring's
|
with {sdg-name}'s *new* `@EnableGemFireAsLastResource` annotation and a combination of Spring's
|
||||||
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction[Transaction Management]
|
{spring-framework-docs}/#transaction[Transaction Management] infrastructure and {sdg-name}'s
|
||||||
infrastructure and {sdg-name}'s `@EnableGemFireAsLastResource` configuration does the trick.
|
`@EnableGemFireAsLastResource` annotation configuration does the trick.
|
||||||
|
|
||||||
The configuration looks like this...
|
The configuration looks like this...
|
||||||
|
|
||||||
@@ -206,7 +211,6 @@ The configuration looks like this...
|
|||||||
@EnableGemFireAsLastResource
|
@EnableGemFireAsLastResource
|
||||||
@EnableTransactionManagement(order = 1)
|
@EnableTransactionManagement(order = 1)
|
||||||
class GeodeConfiguration {
|
class GeodeConfiguration {
|
||||||
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
@@ -220,7 +224,7 @@ where Spring's `@EnableTransactionManagement` annotation is also specified.
|
|||||||
that is not `Integer.MAX_VALUE` or `Integer.MIN_VALUE` (defaults to `Integer.MAX_VALUE`).
|
that is not `Integer.MAX_VALUE` or `Integer.MIN_VALUE` (defaults to `Integer.MAX_VALUE`).
|
||||||
|
|
||||||
Of course, hopefully you are aware that you also need to configure Spring's `JtaTransactionManager`
|
Of course, hopefully you are aware that you also need to configure Spring's `JtaTransactionManager`
|
||||||
when using JTA Transactions like so..
|
when using JTA transactions like so..
|
||||||
|
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
@@ -236,18 +240,18 @@ public JtaTransactionManager transactionManager(UserTransaction userTransaction)
|
|||||||
----
|
----
|
||||||
|
|
||||||
NOTE: The configuration in section <<apis:transaction-management>> does *not* apply here.
|
NOTE: The configuration in section <<apis:transaction-management>> does *not* apply here.
|
||||||
The use of {sdg-name}'s `GemfireTransactionManager` is applicable only in "Local", Cache Transactions,
|
The use of {sdg-name}'s `GemfireTransactionManager` is applicable in "Local-only", Cache Transactions,
|
||||||
*not* "Global", JTA Transactions. Therefore, you do *not* configure the SDG `GemfireTransactionManager` in this case.
|
*not* "Global", JTA Transactions. Therefore, you do *not* configure the SDG `GemfireTransactionManager` in this case.
|
||||||
You configure Spring's `JtaTransactionManager` as shown above.
|
You configure Spring's `JtaTransactionManager` as shown above.
|
||||||
|
|
||||||
For more details on using _Spring's Transaction Management_ with JTA,
|
For more details on using _Spring's Transaction Management_ with JTA,
|
||||||
see https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction-application-server-integration[here].
|
see {spring-framework-docs}/#transaction-application-server-integration[here].
|
||||||
|
|
||||||
Effectively, {sdg-name}'s `@EnableGemFireAsLastResource` annotation imports configuration containing 2 Aspect
|
Effectively, {sdg-name}'s `@EnableGemFireAsLastResource` annotation imports configuration containing 2 Aspect
|
||||||
bean definitions that handles the {data-store-name} `o.a.g.ra.GFConnectionFactory.getConnection()`
|
bean definitions that handles the {data-store-name} `o.a.g.ra.GFConnectionFactory.getConnection()`
|
||||||
and `o.a.g.ra.GFConnection.close()` operations at the appropriate points during the transactional operation.
|
and `o.a.g.ra.GFConnection.close()` operations at the appropriate points during the transactional operation.
|
||||||
|
|
||||||
Specifically, the correct sequence of events are...
|
Specifically, the correct sequence of events follow:
|
||||||
|
|
||||||
1. `jtaTransation.begin()`
|
1. `jtaTransation.begin()`
|
||||||
|
|
||||||
@@ -261,19 +265,20 @@ Specifically, the correct sequence of events are...
|
|||||||
|
|
||||||
This is consistent with how you, as the application developer, would code this manually if you had to use the JTA API
|
This is consistent with how you, as the application developer, would code this manually if you had to use the JTA API
|
||||||
+ {data-store-name} API yourself, as shown in the
|
+ {data-store-name} API yourself, as shown in the
|
||||||
{data-store-name} https://gemfire90.docs.pivotal.io/geode/developing/transactions/jca_adapter_example.html#concept_swv_z2p_wk[example].
|
{data-store-name} {apache-geode-docs}/developing/transactions/jca_adapter_example.html#concept_swv_z2p_wk[example].
|
||||||
|
|
||||||
Thankfully, Spring does the heavy lifting for you and all you need do after applying the appropriate configuration
|
Thankfully, Spring does the heavy lifting for you and all you need to do after applying the appropriate configuration
|
||||||
(shown above) is...
|
(shown above) is:
|
||||||
|
|
||||||
|
.Declaring a service method as @Transactional
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
class MyTransactionalService ... {
|
class MyTransactionalService {
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public <Return-Type> someTransactionalServiceMethod() {
|
public <Return-Type> someTransactionalServiceMethod() {
|
||||||
// perform business logic interacting with and accessing multiple JTA resources atomically, here
|
// perform business logic interacting with and accessing multiple JTA resources atomically
|
||||||
}
|
}
|
||||||
|
|
||||||
...
|
...
|
||||||
@@ -281,7 +286,7 @@ class MyTransactionalService ... {
|
|||||||
----
|
----
|
||||||
|
|
||||||
#1 & #4 above are appropriately handled for you by Spring's JTA based `PlatformTransactionManager` once the
|
#1 & #4 above are appropriately handled for you by Spring's JTA based `PlatformTransactionManager` once the
|
||||||
`@Transactional` boundary is entered by your application (i.e. when the `MyTransactionSerivce.someTransactionalServiceMethod()`
|
`@Transactional` boundary is entered by your application (i.e. when the `MyTransactionService.someTransactionalServiceMethod()`
|
||||||
is called).
|
is called).
|
||||||
|
|
||||||
#2 & #3 are handled by {sdg-name}'s new Aspects enabled with the `@EnableGemFireAsLastResource` annotation.
|
#2 & #3 are handled by {sdg-name}'s new Aspects enabled with the `@EnableGemFireAsLastResource` annotation.
|
||||||
@@ -290,6 +295,7 @@ is called).
|
|||||||
|
|
||||||
Indeed, with the appropriate logging configured, you will see the correct sequence of events...
|
Indeed, with the appropriate logging configured, you will see the correct sequence of events...
|
||||||
|
|
||||||
|
.Transaction Log Output
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Getting transaction for [example.app.service.MessageService.send]
|
2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Getting transaction for [example.app.service.MessageService.send]
|
||||||
@@ -306,12 +312,25 @@ JSON : [{"id":"MSG0000000000","message":"SENT"}] ]
|
|||||||
2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionClosingAspect - Closed {data-store-name} Connection @ [Reference [...]]
|
2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionClosingAspect - Closed {data-store-name} Connection @ [Reference [...]]
|
||||||
----
|
----
|
||||||
|
|
||||||
When using transactions, it may be desirable to register a listener to perform certain actions before or after the
|
For more details on using {data-store-name} cache-level transactions, see <<apis:transaction-management,here>>.
|
||||||
transaction commits, or after a rollback occurs. {sdg-name} makes it easy to create listeners that will be invoked
|
|
||||||
during specific phases of a transaction with the `@TransactionalEventListener` annotation. Methods annotated with
|
|
||||||
`@TransactionalEventListener` (as shown below) will be notified of events published from transactional methods, during
|
|
||||||
the specified `phase`.
|
|
||||||
|
|
||||||
|
For more details on using {data-store-name} in JTA transactions,
|
||||||
|
see https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html[here].
|
||||||
|
|
||||||
|
For more details on configuring {data-store-name} as a "_Last Resource_",
|
||||||
|
see https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[here].
|
||||||
|
|
||||||
|
[[apis:transaction-event-listener]]
|
||||||
|
== TransactionEventListener
|
||||||
|
|
||||||
|
When using transactions, it may be desirable to register a listener to perform certain actions before or after the
|
||||||
|
transaction commits, or after a rollback occurs.
|
||||||
|
|
||||||
|
{sdg-name} makes it easy to create listeners that will be invoked during specific phases of a transaction with the
|
||||||
|
`@TransactionalEventListener` annotation. Methods annotated with `@TransactionalEventListener` (as shown below) will be
|
||||||
|
notified of events published from transactional methods, during the specified `phase`.
|
||||||
|
|
||||||
|
.After Transaction Commit Event Listener
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||||
@@ -320,36 +339,33 @@ public void handleAfterCommit(MyEvent event) {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
Inorder for the above method to be invoked, you must publish an event from within your transaction, like below.
|
Inorder for the above method to be invoked, you must publish an event from within your transaction, like below:
|
||||||
|
|
||||||
|
.Publishing a Transactional Event
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
class MyTransactionalService ... {
|
class MyTransactionalService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private final ApplicationEventPublisher publisher;
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public <Return-Type> someTransactionalServiceMethod() {
|
public <Return-Type> someTransactionalServiceMethod() {
|
||||||
// perform business logic interacting with and accessing multiple JTA resources atomically, here
|
|
||||||
publisher.publishEvent(new MyEvent(...));
|
// Perform business logic interacting with and accessing multiple transactional resources atomically, then...
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(new MyEvent(...));
|
||||||
}
|
}
|
||||||
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
The `@TransactionalEventListener` annotation allows you to specify the transaction `phase` at which it will be invoked;
|
The `@TransactionalEventListener` annotation allows you to specify the transaction `phase` in which the event handler
|
||||||
the options are `AFTER_COMMIT`, `AFTER_COMPLETION`, `AFTER_ROLLBACK`, and `BEFORE_COMMIT`. If not specified, `phase`
|
method will be invoked. Options include: `AFTER_COMMIT`, `AFTER_COMPLETION`, `AFTER_ROLLBACK`, and `BEFORE_COMMIT`.
|
||||||
defaults to `AFTER_COMMIT`. If you wish the listener to be called even when no transaction is running, you may set
|
If not specified, the `phase` defaults to `AFTER_COMMIT`. If you wish the listener to be called even when no transaction
|
||||||
`fallbackExecution` to true.
|
is present, you may set `fallbackExecution` to `true`.
|
||||||
|
|
||||||
For more details on using {data-store-name} in JTA transactions,
|
|
||||||
see https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html[here].
|
|
||||||
|
|
||||||
For more details on configuring {data-store-name} as a "_Last Resource_",
|
|
||||||
see https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[here].
|
|
||||||
|
|
||||||
:leveloffset: +1
|
:leveloffset: +1
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user