Skip to content

JdbcTemplate closes connection after update and Hikari performs a rollback before JpaTransactionManager commit #33993

@BbIKTOP

Description

@BbIKTOP

Affects: Spring Boot 3.3.5

I asked on stackoverflow and also found similar questions there:

https://stackoverflow.com/questions/78022351/spring-boot-jpa-transaction-is-committing-but-record-is-not-getting-inserted
https://stackoverflow.com/questions/78863344/frequent-rollback-on-connection-close-in-spring-boot-with-hikaricp-and-mariadb

The problem:

Simple table:

CREATE TABLE table_master
(
    id       INTEGER NOT NULL,
    name     VARCHAR(200),
    CONSTRAINT t_master_pk PRIMARY KEY (id)
);

Test:

@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Slf4j
class JdbcTest {

    private DataSource fbDataSource;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @BeforeEach
    public void setUp() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:firebirdsql://localhost:3055//opt/fb/db/DBGDB");
        config.setUsername("user");
        config.setPassword("passwd");
        config.setAutoCommit(false);
        fbDataSource = new HikariDataSource(config);
    }

    private static final String insertQuery = "INSERT INTO table_master(id, name) VALUES(?, ?)";
    private static final String cntQuery = "SELECT COUNT(*) FROM table_master";

    @Test
    public void testFbLoad() throws SQLException {
        JdbcTemplate fbJdbcTemplate = new JdbcTemplate(fbDataSource);
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
        def.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_COMMITTED);
        TransactionStatus status = transactionManager.getTransaction(def);

        if (fbJdbcTemplate.update(insertQuery, 1, "Row") == 0) {
            throw new RuntimeException("Cannot insert row");
        }
        transactionManager.commit(status);

        Integer cnt = fbJdbcTemplate.queryForObject(cntQuery, Integer.class);
        log.info("Rows in table_master: {}", cnt);
    }

Log:

2024-11-30T04:10:31.534+02:00 DEBUG 15966 --- [    Test worker] o.h.e.t.internal.TransactionImpl         : On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
2024-11-30T04:10:31.535+02:00 DEBUG 15966 --- [    Test worker] o.h.e.t.internal.TransactionImpl         : begin
2024-11-30T04:10:31.536+02:00 DEBUG 15966 --- [    Test worker] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@ea34dee]
2024-11-30T04:10:31.536+02:00 DEBUG 15966 --- [    Test worker] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2024-11-30T04:10:31.537+02:00 DEBUG 15966 --- [    Test worker] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [INSERT INTO table_master(id, name) VALUES(?, ?)]
2024-11-30T04:10:31.537+02:00 DEBUG 15966 --- [    Test worker] o.s.jdbc.datasource.DataSourceUtils      : Fetching JDBC Connection from DataSource
2024-11-30T04:10:31.544+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.553+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.553+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.567+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.568+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.570+02:00 DEBUG 15966 --- [    Test worker] o.f.jaybird.xca.FBManagedConnection      : End called: Xid[413118226]
2024-11-30T04:10:31.573+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.573+02:00 DEBUG 15966 --- [    Test worker] o.f.gds.ng.wire.AbstractWireOperations   : readStatusVector arg:isc_arg_gds int: 0
2024-11-30T04:10:31.574+02:00 DEBUG 15966 --- [    Test worker] com.zaxxer.hikari.pool.ProxyConnection   : HikariPool-1 - Executed rollback on connection org.firebirdsql.jdbc.FBConnection@394e21b9 due to dirty commit state on close().
2024-11-30T04:10:31.574+02:00 DEBUG 15966 --- [    Test worker] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2024-11-30T04:10:31.574+02:00 DEBUG 15966 --- [    Test worker] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(865867007<open>)]
2024-11-30T04:10:31.574+02:00 DEBUG 15966 --- [    Test worker] o.h.e.t.internal.TransactionImpl         : committing
2024-11-30T04:10:31.575+02:00 DEBUG 15966 --- [    Test worker] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(865867007<open>)] after transaction

Problem:

No data inserted due to:

2024-11-30T04:10:31.574+02:00 DEBUG 15966 --- [    Test worker] com.zaxxer.hikari.pool.ProxyConnection   : HikariPool-1 - Executed rollback on connection org.firebirdsql.jdbc.FBConnection@394e21b9 due to dirty commit state on close().

Reason:

JdbcTemplate closes connection in the update method. Hikari rolls the transaction back due to the connection' dirty state then. Then JpaTransactionManager tries to commit it but it was already rolled back. So, the example from the Spring docs is not working.

Stack:

doCloseConnection:406, DataSourceUtils (org.springframework.jdbc.datasource)
doReleaseConnection:393, DataSourceUtils (org.springframework.jdbc.datasource)
releaseConnection:360, DataSourceUtils (org.springframework.jdbc.datasource)
beforeCompletion:525, DataSourceUtils$ConnectionSynchronization (org.springframework.jdbc.datasource)
triggerBeforeCompletion:108, TransactionSynchronizationUtils (org.springframework.transaction.support)
triggerBeforeCompletion:996, AbstractPlatformTransactionManager (org.springframework.transaction.support)
processCommit:776, AbstractPlatformTransactionManager (org.springframework.transaction.support)
commit:758, AbstractPlatformTransactionManager (org.springframework.transaction.support)
testFbLoad:105, JdbcTest (com.freewayfleet.dbreplicator)

Metadata

Metadata

Assignees

No one assigned

    Labels

    for: stackoverflowA question that's better suited to stackoverflow.com

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions