spring-projects / spring-projects/spring-framework

Nested @TransactionalEventListener with BEFORE_COMMIT and REQUIRES_NEW may leave JDBC connections checked out

Open
#37,084 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

We observed an unexpected behavior when using nested @TransactionalEventListeners together with Propagation.REQUIRES_NEW.

Environment

  • Spring Boot: 3.5.14
  • Spring Framework: 6.2.19
  • Hibernate ORM: 6.6.53.Final
  • HikariCP
  • JpaTransactionManager
  • Java 21

Scenario

The application has the following event flow:

@Transactional
   └── publish(Event1)
           └── @TransactionalEventListener(AFTER_COMMIT)
                   ├── @Transactional(REQUIRES_NEW)
                   │       └── publish(Event2)
                   └── transaction commits
                               └── @TransactionalEventListener(BEFORE_COMMIT)
                                       └── @Transactional(REQUIRES_NEW)

The project attached below is a minimal reproducer.

Repository:
https://github.com/aytacdereli/spring-transactional-event-bug

Expected behavior

Every REQUIRES_NEW transaction should complete normally and release its JDBC connection back to HikariCP after commit.

Actual behavior

Occasionally one of the JDBC connections remains checked out after the transaction has completed.
After several executions, Hikari's active connection count increases and eventually the pool becomes exhausted.
No exception is thrown.

Additional observations

  • Removing the intermediate @TransactionalEventListener completely eliminates the issue.
  • Using only a single transactional event listener does not reproduce the problem.
  • REQUIRES_NEW is executed in a different Spring bean (proxy is applied correctly).
  • No @Async is used for the BEFORE_COMMIT listener.
  • The behavior is reproducible with the attached minimal project.

At this point I am not sure whether this is an intended limitation of nested @TransactionalEventListeners or a transaction lifecycle issue in Spring Framework.
Any guidance would be appreciated.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the linked minimal reproducer with Spring Framework, JpaTransactionManager, nested @TransactionalEventListener callbacks, and REQUIRES_NEW transactions. Start by tracing transaction lifecycle and JDBC connection handling around the AFTER_COMMIT and BEFORE_COMMIT listeners. Done means identifying the lifecycle condition that leaves a connection checked out and confirming repeated executions return all connections to HikariCP without pool exhaustion.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.