spring-framework icon indicating copy to clipboard operation
spring-framework copied to clipboard

continued support for CallbackPreferringPlatformTransactionManager for spring-data-couchbase to implement @Transactional

Open mikereiche opened this issue 3 years ago • 5 comments

Affects: 2.7


spring-data-couchbase would like to support @Transactional support. Couchbase's transaction management aligns with the CallbackPreferringPlatformTransactionManager. There is currently support for CallbackPreferringPlatformManager in TransactionAspectSupport. invokeWithinTransaction() https://github.com/spring-projects/spring-framework/blob/5378572b00d5b9bc6978d117359b059412773288/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java#L415 https://github.com/spring-projects/spring-framework/issues/13906 I understood from @mp911de that had been added solely for Websphere and may be discontinued, although it is not tagged as deprecated. We are wondering if spring-data-couchbase can rely on it for support @Transactional. Thanks.

mikereiche avatar Apr 26 '22 22:04 mikereiche

For further context, the Couchbase transactions API is based around the user providing their transactional logic inside a lambda, that we can retry as needed. A simple transaction could look like this:

cluster.transactions().run(ctx -> {
    // User's transaction goes inside the lambda here
    ctx.insert(collection, "doc1", doc1Content);

    var doc2 = ctx.get(collection, "doc2");
    ctx.replace(doc2, doc2Content);
});

In a retry scenario, which can include a write-write conflict with another transaction, this transaction may be rolled back and then the user's lambda run again. This is a core and essential part of our transaction implementation.

With an @Transactional-annotated method we need to be able to retry the entire method, for the same reason. (We will document that the method may be retried and the user needs to ensure that it is side-effect free.)

CallbackPreferringPlatformTransactionManager seems to be the only way for us to achieve this. If there is another path, then please let us know. (In particular, one limitation of CallbackPreferringPlatformTransactionManager is that we cannot also implement reactive transactions with it.)

programmatix avatar Apr 27 '22 09:04 programmatix

@sdeleuze @jhoeller @mp911de @daschl @programmatix

Hi folks - I was wondering if you have any input on this?
We are also considering providing our own CouchbaseTransactionInterceptor bean that overrides invokeWithinTransaction() such that it does retries on failures.

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static class TransactionInterception {

 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource,
   CouchbaseTransactionManager txManager) {
  TransactionInterceptor interceptor = new CouchbaseTransactionInterceptor();
  interceptor.setTransactionAttributeSource(transactionAttributeSource);
  if (txManager != null) {
   interceptor.setTransactionManager(txManager);
  }
  return interceptor;
 }
 }

mikereiche avatar May 03 '22 15:05 mikereiche

One more use case for transaction retries is CockroachDB. Retry is needed for basically any transaction. There's example of an aspect around @Transactional, but I cannot get it to work with e.g. JpaRepository.save method.

Coroutine support is highly desirable, too.

Maybe TransactionInterceptor could be customizable to accomodate custom logic around transactional invocations.

Will appreciate any input on how to reliably intercept wide range of ways to wrap a piece of code in a transaction (spring's @Transactional, java's @Transactional, TransactionTemplate)

gumanoid avatar Jul 28 '22 20:07 gumanoid

@gumanoid - it's possible to override TransactionInterceptor with your own class like we did for Couchbase. And define transactionInterceptor() bean in your configuration (the post just above yours).

https://github.com/spring-projects/spring-data-couchbase/blob/main/src/main/java/org/springframework/data/couchbase/transaction/CouchbaseTransactionInterceptor.java

spring.main.allow-bean-definition-overriding=true

mikereiche avatar Jul 28 '22 21:07 mikereiche

@mikereiche bean overriding is disabled by default for a good reason, I'm trying to avoid it. Moreover, simply overriding TransactionInterceptor bean won't cover all cases I need - for instance, JpaRepository.save gets it's transaction via TransactionalRepositoryProxyPostProcessor, which instantiates original TransactionInterceptor no matter what beans you've overriden.

gumanoid avatar Jul 29 '22 23:07 gumanoid

As for the original purpose of this ticket, we have no immediate plans to drop the CallbackPreferringPlatformTransactionManager SPI. Even once it might not be needed for WebSphere anymore, it still remains as an SPI variant for other transaction manager implementations.

As for retry support and TransactionInterceptor extensions/replacement, if there is any concrete feature that we can provide there, feel free to create a dedicated ticket for it.

jhoeller avatar Nov 25 '23 14:11 jhoeller