Affects: 5.3.22

I am trying to add a secondary DataSource to my application. Therefore, I have made sure I have 2 instances of the following beans: - DataSource - EntityManagerFactory - PlatformTransactionManager

I created this little test:

@SpringBootTest
class ReplicaTest {
  @Inject private PlatformTransactionManager masterTransactionManager;
  @Inject private EntityManager masterEntityManager;

  @Qualifier(ReplicaDataSourceBeanNames.TRANSACTION_MANAGER)
  @Inject
  private PlatformTransactionManager replicaTransactionManager;
  @Qualifier(ReplicaDataSourceBeanNames.ENTITY_MANAGER_FACTORY)
  @Inject
  private EntityManager replicaEntityManager;

  @Test
  void test1() {
    masterTransactionTemplate.execute(
            s -> {
              Foo newFoo = new Foo();
              replicaEntityManager.persist(newFoo);
              return newFoo;
            });
  }

 @Test
  void test2() {
    replicaEntityManager.persist(newFoo);
  }
}

What happens: test1 does not fail while test2 fails with javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call. What I expect: both tests should fail since replicaEntityManager has been linked to replicaTransactionManager during the configuration phase.

SharedEntityManagerCreator relies on TransactionSynchronizationManager.isActualTransactionActive() to decide wheter a transaction is active. But it does not discriminate the transaction by originating TransactionManager.

Spring allows to qualitfy the requested TransactionManager in multiple places: - https://github.com/spring-projects/spring-framework/blob/5e808ad0183a63944ab08017a13cbc7ed75bc581/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java#L129 - https://github.com/spring-projects/spring-data-jpa/blob/88dffa8e90caa1cb39345decd6d697318210f5a8/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/config/EnableJpaRepositories.java#L138

But at the same time relies heavily on TransactionSynchronizationManager.isActualTransactionActive() without carring about the originating transaction manager.

So looks like a bug to me.

Comment From: reda-alaoui

Here is a reproducer: https://github.com/Cosium/spring-framework/blob/2332bc659f1bb089da1b98b26f6ca572face29ab/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateMultiEntityManagerFactoryIntegrationTests.java#L77-L77

The test will fail because sharedEntityManager.persist(person) will find the wrong active TransactionManager. Note that sharedEntityManager is controlled by transactionManager, not transactionManager2.

Comment From: bclozel

Closing in favor of #29371