Reputation: 404
I am going in a really narrow scenario since I'm using embedded tomcat 10.1
, along with jooq 3.19
and jersey 3.1
.
What I am trying to achieve is to create my own @Interceptor
that is supposed to act as a @Transactional
annotation. I managed to create jooq's DSLContext
in the RequestScoped
and pass it to the interceptor and all the repositories instances within the request, share the same DSLContext
. Then in the interceptor the idea was to wrap method's body within a jooq transaction. Autocommit is set to false.
I found out that any query performed on a database is executed in a different transaction, so the transaction is not shared. It is not shared even within single repository as in TenantRepository
class.
How to make DSLContext
aware that is in transaction context?
Am I missing something obvious? Is DSLContext
right object to be injected?
Also if you think I am far away of implementing Transactional interface please let me know what is ahead of me since I don't really want to go to a rabbit hole.
Why all of this? I had an idea that it would be really nice to have service and repository layer split so that there is no DSLContext injected on the Service layer classes.
Was inspired by this article: https://blog.dejavu.sk/intercepting-jersey-resource-method-calls/
I have attached the code below, thank you all in advance!
package com.example.config;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jooq.DSLContext;
public class TransactionInterceptor implements MethodInterceptor {
private Provider<DSLContext> serviceProvider;
@Inject
public TransactionInterceptor(Provider<DSLContext> serviceProvider) {
this.serviceProvider = serviceProvider;
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
DSLContext dslContext = serviceProvider.get();
dslContext.transactionResult(configuration -> {
return methodInvocation.proceed();
});
return null;
}
}
@Service
public class TenantService {
private final TenantRepository tenantRepository;
private final ShopRepository shopRepository;
@Inject
public TenantService(TenantRepository tenantRepository,
ShopRepository shopRepository) {
this.tenantRepository = tenantRepository;
this.shopRepository = shopRepository;
}
@TransactionalMethod
public void create(TenantCreateRequest createRequest) {
UUID tenantId = tenantRepository.insert(createRequest.getName());
UUID shopId = shopRepository.insert(tenantId, createRequest.getShop().toShop());
}
}
Then I added another 2 queries to see if they are executed within the same transaction, but they are not.
@Service
public class TenantRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(TenantService.class);
private final DSLContext dsl;
@Inject
public TenantRepository(DSLContext dsl) {
this.dsl = dsl;
}
public UUID insert(String name) {
LOGGER.info("Current transaction: " + dsl.select(field("txid_current()", BigInteger.class))
.fetchOneInto(BigInteger.class));
UUID tenantId = UUID.randomUUID();
dsl.insertInto(TENANT)
.set(TENANT.TENANT_ID, tenantId)
.set(TENANT.CREATED_AT, LocalDateTime.now())
.set(TENANT.NAME, name)
.execute();
LOGGER.info("Current transaction: " + dsl.select(field("txid_current()", BigInteger.class))
.fetchOneInto(BigInteger.class));
return tenantId;
}
}
Upvotes: 0
Views: 28