I am in the process of experimenting with Quarkus, building a small REST application. For this I have elected to use the Agroal datasource but neither Panache or plain Hibernate (as is shown in their examples), but rather I'm using plaing JDBC.
For database interaction I have created a small service that injects the AgroalDataSource and uses it to open up database connections. Said service exposes two methods one for running no transactional queries and one or transactional ones. For the first part everything works fine, but when I attempt to update a database entry the action fails upon attempting to commit the connection.
public <E> E update(TransactionalRunner<E> runner) {
try (var connection = dataSource.getConnection()) {
return attemptTransactional(runner, connection);
} catch (SQLException e) {
log.error("Establishing a database connection has failed", e);
throw new DataAccessException(e);
}
}
private <E> E attemptTransactional(TransactionalRunner<E> runner, Connection connection) {
try {
connection.setAutoCommit(Boolean.FALSE);
E result = runner.run(new QueryRunner(), connection);
connection.commit();
return result;
} catch (SQLException e) {
try {
log.error("Committing a transaction has failed. Attempting rollback", e);
DbUtils.rollback(connection);
throw new DataAccessException(e);
} catch (SQLException ex) {
log.error("Rolling back a transaction has failed. Giving up...", ex);
throw new DataAccessException(ex);
}
}
}
The stacktrace I'm getting is the following:
2019-12-21 14:25:59,350 ERROR [com.ari.rev.dat.DatabaseAccessService] (vert.x-worker-thread-1) Committing a transaction has failed. Attempting rollback: java.sql.SQLException: Attempting to commit while taking part in a transaction
at io.agroal.pool.wrapper.ConnectionWrapper.commit(ConnectionWrapper.java:183)
at com.ariskourt.revolut.database.DatabaseAccessService.attemptTransactional(DatabaseAccessService.java:44)
at com.ariskourt.revolut.database.DatabaseAccessService.update(DatabaseAccessService.java:33)
at com.ariskourt.revolut.database.DatabaseAccessService_ClientProxy.update(DatabaseAccessService_ClientProxy.zig:114)
at com.ariskourt.revolut.services.AccountTransferService.transferAmount(AccountTransferService.java:66)
at com.ariskourt.revolut.services.AccountTransferService_Subclass.transferAmount$$superaccessor2(AccountTransferService_Subclass.zig:164)
at com.ariskourt.revolut.services.AccountTransferService_Subclass$$function$$2.apply(AccountTransferService_Subclass$$function$$2.zig:51)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:119)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:92)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:32)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:53)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:26)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(TransactionalInterceptorRequired_Bean.zig:168)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
I'm using the default Agroal datasource offered by Quarkus without any custom configuration. As for the QueryRunner
these are just part of the Apache DbUtils suite.
Has anyone got any idea on how to resolve this?