title: Spring opens a new transaction for each JpaRepository method that is called within an @Transactional annotated method
body: <p>I have a method that is annotated with <code>@Transactional</code>. That should mean that any database queries that are fired within this method should all use the same transaction. But in reality that doesn't happen. What does happen is that a transaction is opened for the method itself but then when the first <code>JpaRepository</code> method is called a new transaction is opened for that particular method call.</p>
  <p>To make matters more complex, For custom repository methods this new transaction is <strong>only</strong> opened when the <code>JpaRepository</code> or the <code>JpaRepository custom method</code> is annotated with <code>@Transactional</code> as well.
  If not i get the following trace log statement about it:</p>
  <blockquote>
  <p>No need to create transaction for
  [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findFirstByIdNotNull]:
  This method is not transactional.</p>
  </blockquote>
  <p>So it doesn't create a new transaction but it also doesn't seem to use the transaction created by the calling method either.</p>
  <p>Heres the repository class:</p>
  <pre><code>@Repository
  public interface LanguageDao extends JpaRepository&lt;Language, Long&gt; {
  
  @Transactional
  public Language findByLanguageCode(String languageCode);
  
  public Language findByIdNotNull();
  
  }
  </code></pre>
  <p>Heres the method that uses different repository methods.</p>
  <pre><code>@Transactional
  public void afterSingletonsInstantiated() {
      languageDao.findByLanguageCode(); //This custom method opens a new transaction, but only because i've annotated this method with @Transactional as well.
      languageDao.findAll(); //This one as well because its a standard JpaRepository method.
      languageDao.findByIdNotNull();//This custom method doesn't because it lacks its own @Transactional annotation.
  }
  </code></pre>
  <p>Heres the @Configuration file, with transaction management and jpa repositories enabled</p>
  <pre><code>@EnableJpaRepositories(basePackages={&quot;DAOs&quot;}, transactionManagerRef = &quot;customTransactionManager&quot;, enableDefaultTransactions = true)
  @EnableTransactionManagement
  @Configuration
  public class RootConfig implements InitializingBean {
  
      @Bean(name = &quot;customTransactionManager&quot;)
      JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
          JpaTransactionManager transactionManager = new JpaTransactionManager();
          transactionManager.setEntityManagerFactory(entityManagerFactory);
          if (shouldCreateInitialLuceneIndex) { 
              EntityManager entityManager = entityManagerFactory.createEntityManager();
              createInitialLuceneIndex(entityManager);
              entityManager.close();
          }
          return transactionManager;
      }
  }
  </code></pre>
  <p>Relevant <code>application.properties</code> settings</p>
  <pre><code>spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
  spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
  spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect
  spring.jpa.open-in-view = false
  </code></pre>
  <p>A bit of actual logs. The first line shows that a transaction for the method <code>afterSingletonsInstantiated</code> is created.</p>
  <pre><code>[TRACE] 2021-11-08 15:32:40.811 [main] TransactionInterceptor - Getting transaction for [config.StartupChecks$$EnhancerBySpringCGLIB$$134b7631.afterSingletonsInstantiated]
  [INFO ] 2021-11-08 15:32:40.815 [main] StartupChecks - Calling sequence table reset procedure
  [DEBUG] 2021-11-08 15:32:40.833 [main] SQL - {call RESET_SEQUENCE_TABLE_VALUES_TO_LATEST_ID_VALUES()}
  [INFO ] 2021-11-08 15:32:41.087 [main] StartupChecks - Sequence tables reset call finished!
  [INFO ] 2021-11-08 15:32:41.087 [main] StartupChecks - doing stuff
  [INFO ] 2021-11-08 15:32:41.087 [main] StartupChecks - testing!
  [TRACE] 2021-11-08 15:32:41.087 [main] TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
  [DEBUG] 2021-11-08 15:32:41.088 [main] SQL - select language0_.id as id1_77_, language0_.dateCreated as datecrea2_77_, language0_.englishLanguageName as englishl3_77_, language0_.languageCode as language4_77_, language0_.rightToLeft as righttol5_77_, language0_.translatedLanguageName as translat6_77_ from languages language0_
  [TRACE] 2021-11-08 15:32:41.091 [main] TransactionInterceptor - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
  [INFO ] 2021-11-08 15:32:41.091 [main] StartupChecks - end test!
  [TRACE] 2021-11-08 15:32:41.091 [main] TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByLanguageCode]
  [DEBUG] 2021-11-08 15:32:41.112 [main] SQL - select language0_.id as id1_77_, language0_.dateCreated as datecrea2_77_, language0_.englishLanguageName as englishl3_77_, language0_.languageCode as language4_77_, language0_.rightToLeft as righttol5_77_, language0_.translatedLanguageName as translat6_77_ from languages language0_ where language0_.languageCode=?
  [TRACE] 2021-11-08 15:32:41.113 [main] TransactionInterceptor - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByLanguageCode]
  [TRACE] 2021-11-08 15:32:41.113 [main] TransactionInterceptor - No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findFirstByIdNotNull]: This method is not transactional.
  [DEBUG] 2021-11-08 15:32:41.115 [main] SQL - select authority0_.ID as id1_7_, authority0_.dateCreated as datecrea2_7_, authority0_.NAME as name3_7_ from AUTHORITY authority0_ where authority0_.ID is not null limit ?
  [TRACE] 2021-11-08 15:32:41.120 [main] TransactionInterceptor - No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findFirstByIdNotNull]: This method is not transactional.
  </code></pre>
  <p>Here is a list of the things that i've already tried.</p>
  <ol>
  <li>Annotate <code>languageDao</code> with @Transactional(propagation = Propagation.SUPPORTS) or
  @Transactional(propagation = Propagation.NESTED). <code>NESTED</code> isn't supported by hibernate and thus this causes an error, This error remains even when i set nestedTransactionAllowed to <code>true</code> on the transactionmanager. The setting <code>SUPPORTS</code> is ignored. The repository still starts a new transaction for each method that is called. (Update: <code>Propagation.MANDATORY</code> has no effect either)</li>
  <li>I've named my transactionmanager <code>customTransactionManager</code> and added this as a parameter to @EnableJpaRepositories like so: <code>@EnableJpaRepositories(basePackages={&quot;DAOs&quot;}, transactionManagerRef = &quot;customTransactionManager&quot;)</code></li>
  <li>I've set <code>enableDefaultTransactions</code> of <code>@EnableJpaRepositories</code> to <code>false</code>. This causes default methods like <code>findAll()</code> and <code>save()</code> to no longer be executed in a transaction by default. However it doesn't force them to use the transaction of the calling method that was annotated with <code>@Transactional</code>.</li>
  </ol>
  <p>So my question is: How do i make the (custom) jpa repositories use the transaction that was started by the calling method?</p>
  <p>EDIT: Here <a href="https://stackoverflow.com/questions/53802031/jpa-spanning-a-transaction-over-multiple-jparepository-method-calls">JPA - Spanning a transaction over multiple JpaRepository method calls</a> a similar problem is described. According to the user spring only uses the existing transaction when the repository implements <code>Repository</code> instead of <code>CrudRepository</code> or <code>JpaRepository</code>. But this is a workaround.</p>
  <p>EDIT 2: My @Transactional annotations keep working when i remove <code>@EnableTransactionManagement</code>. According to <a href="https://stackoverflow.com/questions/40046116/spring-boot-with-spring-transactional-works-without-enabling-transactional-mana">this post</a> that can occur when i use <code>spring-boot-starter-jdbc</code> or <code>spring-boot-starter-data-jpa as a dependency</code>, which i do. Could these dependencies somehow interfere with the normal working of the transaction manager?</p>