NOT_SUPPORTED Propagation in spring @transaction while using spring data VMware GemFire
search cancel

NOT_SUPPORTED Propagation in spring @transaction while using spring data VMware GemFire

book

Article ID: 294346

calendar_today

Updated On:

Products

VMware Tanzu Gemfire

Issue/Introduction

When implementing VMware GemFire transactions with Spring @Transaction, the option to make propagation not required is not working.

For example:
@Transactional("transactionManager")
public void method(){
call method2();
call method3();
call method4();
}
public void method2(){
//do something
}
public void method4(){
//do something
}
@Transactional(value = "transactionManager", propagation = Propagation.NOT_SUPPORTED)
public void method3(){
//perform some action on global region using function
}


Is Propagation.NOT_SUPPORTED supported for a VMware GemFire cache transaction? 


Environment

Product Version: 9.8

Resolution

Is Propagation.NOT_SUPPORTED supported for a VMware GemFire cache transaction?

VMware GemFire, and by extension SDG, supports Propagation.NOT_SUPPORTED, which “suspends” the current transaction.

SDG added support for transaction suspend or resume in SDG 1.9, which is based on VMware GemFire 8.x. See SGF-598 - “Add support for suspend and resume in GemfireTransactionManager” for more details.

It is important to understand that Spring’ transaction management and infrastructure, and specifically the “declarative” arrangement, is based on Spring AOP.

From a high level, it creates an (AOP) “proxy” “around” the transactionally declared Spring managed bean in order to advise the required transactional bean class and/or method(s).

This is necessary to apply the correct transaction scope (class or method and interception point) as well as behavior (advice), as defined by the transactional semantics declared in configuration for the (physical or logical) transaction.

In short, we must restructure the application code in order for the “logical” transaction semantics (Propagation.NOT_SUPPORTED) on methods to apply correctly.

There are two options to resolve this issue.
 

Option 1

First, it is recommended to restructure the application code appropriately.

For example:
@Service
class OuterTransactionalService { 
  @Autowired
  private InnerTransactionalService inner;
  // this method replaces "method" in the customer's hypothetical example
  @Transactional
  public void someCompoundTransactionalOperation() {
      inner.method2();
      inner.method3();
      inner.method4();
  }
  // ...
}
AND
@Service
@Transactional
class InnerTransactionalService {
  public void method2() {
    // perform some Region operations
  }
  @Transactional(propagation = Propagation.NOT_SUPPORTED)
  public void method3() {
    // invoke Function
  }
  public void method4() {
    // perform some other Region operations
  }
}
This approach works because the OuterTransactionalService gets a reference injection to the “PROXY” for the InnerTransactionalService, and not this object directly. 

As a result, all transactionally proxied method invocations on the InnerTransactionalService from the OuterTransactionalService object go through the PROXY for the InnerTransactionalService and thereby apply the transactional advice correctly, as intended.
 

Option 2

The second option is to use AspectJ compiled Aspects and Spring’s Load-time Weaving (LTW) with AspectJ. Please not that this option modifies the actual application compiled byte code and you must be careful of this on different Java VMs.

One nice thing about using the AspectJ compiler approach is you would not be required to restructure the application code.