Skip to content

ResourcelessTransactionManager doesn't seem to support TransactionDefinition.PROGRAGATION_SUPPORTS #5066

@pevdh

Description

@pevdh

Bug description
When using ResourcelessTransactionManager, calling a method with @Transactional(propagation = Propagation.SUPPORTS) followed by a method with @Transactional(propagation = Propagation.REQUIRED_NEW) will result in a TransactionSuspensionNotSupportedException.

It seems ResourcelessTransactionManager creates an inactive ResourcelessTransaction during the first method call. The second method call then tries to suspend this "existing transaction".

Environment
Spring Framework 6.2.11
Spring Batch 5.2.3
Java 17

Expected behavior
We bumped into this issue while migrating a code base from Spring Batch 4 to Spring Batch 5.
ResourcelessTransactionManager not understanding Propagation.SUPPORTS presents a problem in Spring Batch 5, as many JobExplorer methods are now annotated with Propagation.SUPPORTS.
As a result, any call to a JobExplorer method (using SUPPORTS) followed by a call to a JobRepository method (using REQUIRES_NEW) consistently fails with a TransactionSuspensionNotSupportedException.

Minimal Complete Reproducible example

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SuspendTransactionExceptionReproducerTest.Config.class})
public class SuspendTransactionExceptionReproducerTest {

    @Resource
    private JobExplorer jobExplorer;

    @Resource
    private JobRepository jobRepository;

    @Test
    public void testSuspendTransactionNotSupportedException() {
        // Step 1: JobExplorer.getJobNames() uses PROPAGATION_SUPPORTS
        // Expected: Execute non-transactionally since no transaction exists
        // Actual: ResourcelessTransactionManager creates a ResourcelessTransaction
        jobExplorer.getJobNames();

        // Step 2: JobRepository.getLastJobExecution() uses PROPAGATION_REQUIRES_NEW
        // Expected: Start a new transaction (no existing transaction to suspend)
        // Actual: Finds the bound ResourcelessTransaction, tries to suspend it
        // Result: TransactionSuspensionNotSupportedException
        jobRepository.getLastJobExecution("test", new JobParameters());
    }

    @Configuration
    @EnableTransactionManagement
    public static class Config {

        @Bean
        public DataSource dataSource() {
            return new EmbeddedDatabaseBuilder()
                    .setType(EmbeddedDatabaseType.H2)
                    .addScript("org/springframework/batch/core/schema-h2.sql")
                    .build();
        }

        @Bean
        public PlatformTransactionManager transactionManager() {
            return new ResourcelessTransactionManager();
        }

        @Bean
        public JobRepositoryFactoryBean jobRepository() {
            JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
            factory.setDataSource(dataSource());
            factory.setTransactionManager(transactionManager());
            return factory;
        }

        @Bean
        public JobExplorerFactoryBean jobExplorer() {
            JobExplorerFactoryBean factory = new JobExplorerFactoryBean();
            factory.setDataSource(dataSource());
            factory.setTransactionManager(transactionManager());
            return factory;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions