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.
Comment From: programmatix
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.)
Comment From: mikereiche
@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;
}
}
Comment From: gumanoid
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
)
Comment From: mikereiche
@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
Comment From: gumanoid
@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.
Comment From: jhoeller
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.