Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring does not clean up db connection registered in afterCompletion callback [SPR-15194] #19759

Closed
spring-issuemaster opened this issue Jan 26, 2017 · 6 comments

Comments

@spring-issuemaster
Copy link
Collaborator

commented Jan 26, 2017

M J opened SPR-15194 and commented

During rollback, when additional database operations are performed using jdbcTemplate, Spring does not clean up the database connection it stores in threadLocal.

When the same thread is later reused on another request, Spring uses this stale and potential invalid ( terminated by server) connection, instead of getting one from the thread pool. This causes "broken pipe" or "communication link failure" exception

See this link for detailed example

http://stackoverflow.com/questions/41860231/springframework-jdbctemplate-database-connection-not-cleanedup-from-threadloca


Affects: 4.2.6

Reference URL: http://stackoverflow.com/questions/41860231/springframework-jdbctemplate-database-connection-not-cleanedup-from-threadloca

Issue Links:

  • #16214 TransactionSynchronizationManager - throw an Exception or log a warning if a Synchronization wants to add a Synchronization and afterCompletion is already called

1 votes, 3 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 27, 2017

Juergen Hoeller commented

Could you elaborate a bit please? Which transaction manager are you using? What's your setup for annotation-driven transactions? The pseudo-code on StackOverflow doesn't really help in debugging this, I'm afraid.

In general, connections are being released once a transaction completes, no matter whether as a commit or rollback. A database operation triggered after a rollback, like sketched on StackOverflow, should just open a new transaction and complete it right after the operation.

Are you possibly trying to use JdbcTemplate within a TransactionSynchronization.afterCompletion callback? At which point is the connection being obtained that you see attached to the thread eventually?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 27, 2017

M J commented

Yes, we are using jdbcTemplate within a TransactionSynchronization.afterCompletion

The psuedo code is confusing because I am trying to show a multi threading issue in a single thread.

Let me update the psuedo code here to make it more clear. Let me break it up into 2 executions of the same thread to be more clear

thread1-run1() {
// First run of some thread from threadpool
  try {

    method1() ;

   } catch(Exception e) {

    method2() // This is called by TransactionSynchronization.afterCompletion. 
    // This is the call that seems to NOT clean up the connection on ThreadLocal
    
   }

}

thread1-run2() {
// same thread as above doing different job
// called after time > mysql wait_timeout

    method2() ;
    // this will throw broken pipe exception
    // when I step through jdbcTemplate and DataSourceUtils
    // I see the connection taken from ThreadLocal and not from the dataSource


}
@Transactional
method1() {

    jdbcTemplate.execute("select 1") ;
    throw new RuntimeException() ;


}


@Transactional
method2() {

    jdbcTemplate.execute("select 1") ;

}

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 27, 2017

M J commented

Using Requires_New for method2 did not help

The transaction manager we use is JpaTransactionManager

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 27, 2017

Juergen Hoeller commented

Seeing that this is triggered from an afterCompletion callback, it is very likely the known issue that we have in #16214: Interleaved transaction synchronizations, in particular new ones registered in another synchronization's afterCompletion callback, do not get fully processed. We should either reject such badly timed registrations altogether... or make them operate outside of any transaction synchronization, in particular without thread-local resources.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 27, 2017

M J commented

Our current workaround is to run afterCompletion database operations in a different thread.

Avoiding jdbcTemplate in afterCompletion and using getConnection from dataSource + straight JDBC seems to work as well as it avoids the threadLocal.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Feb 9, 2017

Juergen Hoeller commented

I've closed that gap now, with synchronization marked as inactive right before we trigger afterCompletion callbacks. As a consequence, our resource handling code won't be fooled into assumping that it still makes sense to register new resource cleanup synchronizations which end up not getting called anymore.

As far as I can tell, this only really affects afterCompletion callbacks which trigger usage of new resources that are not part of the current transaction already. With this change, they are effectively going to execute in their own scope now, just like when running outside of any enclosing transaction to begin with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.