TransactionSynchronizationManager is kind of inconsistent in how it deals with "resources".

In the code I see:

    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");

suggesting that these resources are bound to a transaction. Further down in the Javadoc of the various methods that handle resource bind/unbind, there is no mention about transaction though, only thread local.

I was kind of caught by surprise that resources are not cleaned up after a transaction completes or stored away and restored on suspend/resume. As the implementation is right now, this resources ThreadLocal is not useful i.e. I could have just used my own ThreadLocal myself.

IMO the transaction implementations should be changed to really bind these resources to a transaction. Otherwise, there is also a potential for a memory leak when somebody binds something to this resources, but doesn't cleanup the value in a TransactionSynchronization which really is transaction bound.

Comment From: jhoeller

That's intentional: The same resource binding is also used for reuse across demarcated scopes in general, even without an actual transaction, e.g. on @Transactional(propagation=SUPPORTS) or for OpenEntityManagerInViewFilter. The javadoc of those methods does not talk about automatic unbinding or even a transaction scope at all either. It's just meant to be a pair of bind/unbind method for a centralized ThreadLocal that all of Spring's transaction manager and data access implementations commonly use, and that integration code can use to interact with the managed resources of those common Spring transaction managers.

Now you could make an argument that there should be a convenient way to actually register a transaction-scoped resource with automatic unbinding, similar to how SimpleTransactionScope is implemented: for example, a bindTransactionScopedResource method that not only delegates to bindResource but also implicitly registers a TransactionSynchronization for unbinding.

Comment From: beikov

Thanks for confirming that the behavior is intended. I still think it is a bit confusing, though I also understand that "it is how it is" at this point.

for example, a bindTransactionScopedResource method that not only delegates to bindResource but also implicitly registers a TransactionSynchronization for unbinding.

IMO this would be a good addition and there should be a callout referring to this variant in the various bind/unbind methods that touch just the thread-local.

Comment From: jhoeller

I'm going with bindSynchronizedResource since that most naturally matches the local terminology in TransactionSynchronizationManager, without sounding BeanFactory Scope like (which would be confusing in its own right). I'm pointing to SimpleTransactionScope in the javadoc there, logically connecting those two.