Skip to main content

What Is Propagation Requires_new?

by
Last updated on 9 min read
Quick Fix Summary: Add @Transactional(propagation = Propagation.REQUIRES_NEW) to any Spring-managed method to force a fresh transaction, even when one's already active. Just ensure your Spring Boot app has transaction management enabled and your database supports ACID transactions.

CONCISE ANSWER

Propagation.REQUIRES_NEW in Spring Boot always kicks off a brand-new, independent transaction, pausing any existing one. That guarantees complete isolation between operations.

What's Happening

Spring Boot's Propagation.REQUIRES_NEW always starts a brand-new transaction, suspending any existing one.

In Spring Boot, transaction propagation defines how a transactional method behaves when called from another transactional context. Propagation.REQUIRES_NEW pauses any existing transaction and launches a completely independent one. Unlike REQUIRED (which joins or creates a transaction but never interrupts), REQUIRES_NEW ensures your method runs with zero interference from its caller's transaction state. That's critical when operations must succeed completely or fail completely, no matter what happens to the caller.

Spring Transaction Management provides the authoritative explanation of propagation behaviors.

Step-by-Step Solution

  1. Enable Transaction Management

    Spring Boot auto-configures transaction management in most cases. That said, it's worth explicitly turning it on with @EnableTransactionManagement in your main application class or configuration class:

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @SpringBootApplication
    @EnableTransactionManagement
    public class MyApp {
        public static void main(String[] args) {
            SpringApplication.run(MyApp.class, args);
        }
    }

    Spring Framework Documentation confirms this is required for proxy-based transaction management.

  2. Annotate Your Method

    Slap @Transactional(propagation = Propagation.REQUIRES_NEW) on any service method that needs its own transaction:

    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class PaymentService {
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void processPayment(Payment payment) {
            // Deduct funds, update ledger, log audit trail
        }
    }
  3. Verify Database Support

    Make sure your database supports transactions. Spring Boot uses the database's transaction manager. For PostgreSQL, MySQL, or Oracle, your application.properties should include:

    spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
    spring.datasource.username=user
    spring.datasource.password=pass
    spring.jpa.hibernate.ddl-auto=validate

    PostgreSQL Documentation states that all modern relational databases support ACID transactions.

    PostgreSQL Documentation confirms ACID compliance for transactional integrity.

If This Didn't Work

  • Verify Transaction Manager Configuration

    If transactions aren't firing, check if Spring Boot auto-configured a transaction manager. For JPA, Spring Boot creates a JpaTransactionManager. For multiple data sources, define a PlatformTransactionManager bean:

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }

    The Spring Framework API documents this interface.

  • Check Rollback Conditions

    Spring rolls back transactions only on unchecked exceptions by default. If your method isn't rolling back, throw a RuntimeException:

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void refundOrder(Order order) {
        if (order.isInvalid()) {
            throw new RuntimeException("Order is invalid");
        }
        // Process refund
    }

    Spring Transaction Management specifies default rollback behavior.

  • Enable Transaction Logging

    Debug propagation issues with transaction interceptor logging:

    logging.level.org.springframework.transaction.interceptor=TRACE

    This reveals whether transactions are being suspended, created, or joined. Check out the Log4j 2 Documentation for configuration details.

Prevention Tips

  • Always Specify Propagation

    Never rely on defaults. Declare propagation behavior explicitly in all @Transactional annotations:

    @Transactional(
        propagation = Propagation.REQUIRES_NEW,
        timeout = 30,
        rollbackFor = {PaymentException.class, SystemException.class}
    )

    This prevents accidental transaction reuse and makes your code clearer.

  • Monitor with Spring Boot Actuator

    Install Spring Boot Actuator to inspect transaction metrics:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    Then expose transaction endpoints in application.properties:

    management.endpoints.web.exposure.include=health,metrics,httptrace,transaction

    Spring Boot Actuator Documentation lists these endpoints.

  • Use Integration Tests

    Validate transactional behavior with integration tests using @DataJpaTest and @Transactional test annotations:

    @SpringBootTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class PaymentServiceTests {
        @Autowired
        private PaymentService paymentService;
    
        @Test
        void testPaymentCreatesNewTransaction() {
            paymentService.processPayment(new Payment());
        }
    }

    This ensures your propagation logic behaves as expected in a real container. See the Spring Boot Testing Documentation for details.

What’s Happening

REQUIRES_NEW always starts a brand-new transaction, suspending any existing one.

REQUIRES_NEW kicks off a fresh transaction every time, even if another transaction is already running. It temporarily pauses the existing one. This is perfect when you need that transaction to finish on its own, no matter what happens in the calling method. Think of it like starting a brand-new conversation instead of piggybacking on the current one. Compare this to REQUIRED, which either joins an existing transaction or starts a new one—it never interrupts what’s already going on.

Spring Transaction Management provides the authoritative explanation of propagation behaviors.

What's Happening

- Propagation.REQUIRES_NEW suspends any existing transaction and starts a completely independent one.

In Spring Boot, transaction propagation determines how a transactional method behaves when called from another transactional context. Propagation.REQUIRES_NEW temporarily suspends any existing transaction and starts a brand-new, independent one. Unlike REQUIRED (which joins or creates a transaction but never interrupts), REQUIRES_NEW guarantees your method runs with zero interference from its caller's transaction state. This becomes crucial when certain operations must complete successfully or fail completely, regardless of what happens to the caller.

Step-by-Step Solution

- Enable transaction management, annotate the method with @Transactional(propagation = Propagation.REQUIRES_NEW), and verify database support.
  1. Enable Transaction Management

    First, make sure your Spring Boot app has transaction management turned on. Add @EnableTransactionManagement to your main application class or configuration class:

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @SpringBootApplication
    @EnableTransactionManagement
    public class MyApp {
        public static void main(String[] args) {
            SpringApplication.run(MyApp.class, args);
        }
    }

    (Honestly, this step trips up a lot of people, so don’t skip it.)

  2. Annotate the Method

    Now, add @Transactional(propagation = Propagation.REQUIRES_NEW) to the method where you want a brand-new transaction:

    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class UserService {
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void createUserWithNewTransaction(User user) {
            // Your business logic goes here
        }
    }
  3. Verify Database Support

    Double-check that your database (PostgreSQL, MySQL, Oracle, etc.) plays nice with transactions. Spring Boot relies on the database’s transaction manager. If you’re using JPA and Hibernate, your application.properties should look something like this:

    spring.jpa.hibernate.ddl-auto=update
    spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
    spring.datasource.username=user
    spring.datasource.password=pass

If This Didn't Work

- Verify transaction manager configuration, check rollback conditions, or enable transaction logging.
  • Verify Transaction Manager Configuration

    If transactions aren't firing, check if Spring Boot auto-configured a transaction manager. For JPA, Spring Boot creates a JpaTransactionManager. For multiple data sources, define a PlatformTransactionManager bean:

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }

    The Spring Framework API documents this interface.

  • Check Rollback Conditions

    Spring rolls back transactions only on unchecked exceptions by default. If your method isn't rolling back, throw a RuntimeException:

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void refundOrder(Order order) {
        if (order.isInvalid()) {
            throw new RuntimeException("Order is invalid");
        }
        // Process refund
    }

    Spring Transaction Management specifies default rollback behavior.

  • Enable Transaction Logging

    Debug propagation issues with transaction interceptor logging:

    logging.level.org.springframework.transaction.interceptor=TRACE

    This reveals whether transactions are being suspended, created, or joined. Check out the Log4j 2 Documentation for configuration details.

Prevention Tips

- Always specify propagation explicitly, monitor with Spring Boot Actuator, and use integration tests.
  • Always Specify Propagation

    Never rely on defaults. Declare propagation behavior explicitly in all @Transactional annotations:

    @Transactional(
        propagation = Propagation.REQUIRES_NEW,
        timeout = 30,
        rollbackFor = {PaymentException.class, SystemException.class}
    )

    This prevents accidental transaction reuse and makes your code clearer.

  • Monitor with Spring Boot Actuator

    Install Spring Boot Actuator to inspect transaction metrics:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    Then expose transaction endpoints in application.properties:

    management.endpoints.web.exposure.include=health,metrics,httptrace,transaction

    Spring Boot Actuator Documentation lists these endpoints.

  • Use Integration Tests

    Validate transactional behavior with integration tests using @DataJpaTest and @Transactional test annotations:

    @SpringBootTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class PaymentServiceTests {
        @Autowired
        private PaymentService paymentService;
    
        @Test
        void testPaymentCreatesNewTransaction() {
            paymentService.processPayment(new Payment());
        }
    }

    This ensures your propagation logic behaves as expected in a real container. See the Spring Boot Testing Documentation for details.

What’s Happening

Propagation in Spring Boot controls how transaction boundaries behave when one transactional method calls another.

REQUIRES_NEW starts a fresh transaction every time, even if another transaction is already running. It temporarily pauses the existing one. This is perfect when you need that transaction to finish on its own, no matter what happens in the calling method. Think of it like starting a brand-new conversation instead of piggybacking on the current one. Compare this to REQUIRED, which either joins an existing transaction or starts a new one—it never interrupts what’s already going on.

Step-by-Step Solution

- Enable transaction management, annotate the method with @Transactional(propagation = Propagation.REQUIRES_NEW), and verify database support.
  1. Enable Transaction Management

    First, make sure your Spring Boot app has transaction management turned on. Add @EnableTransactionManagement to your main application class or configuration class:

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @SpringBootApplication
    @EnableTransactionManagement
    public class MyApp {
        public static void main(String[] args) {
            SpringApplication.run(MyApp.class, args);
        }
    }

    (Honestly, this step trips up a lot of people, so don’t skip it.)

  2. Annotate the Method

    Now, add @Transactional(propagation = Propagation.REQUIRES_NEW) to the method where you want a brand-new transaction:

    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class UserService {
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void createUserWithNewTransaction(User user) {
            // Your business logic goes here
        }
    }
  3. Verify Database Support

    Double-check that your database (PostgreSQL, MySQL, Oracle, etc.) plays nice with transactions. Spring Boot relies on the database’s transaction manager. If you’re using JPA and Hibernate, your application.properties should look something like this:

    spring.jpa.hibernate.ddl-auto=update
    spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
    spring.datasource.username=user
    spring.datasource.password=pass

If It Didn’t Work

- Check transaction manager configuration, test with exceptions, or review propagation behavior.
  • Check Transaction Manager Configuration

    If transactions aren’t firing up, your transaction manager might be misconfigured. Spring Boot usually auto-configures a JpaTransactionManager for JPA. But if you’re juggling multiple data sources, you’ll need to define a PlatformTransactionManager bean yourself:

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }

    Source: Spring Framework Documentation

  • Test with Exceptions

    If your transaction isn’t rolling back when it should, you might be throwing the wrong kind of exception. Spring only rolls back transactions on unchecked exceptions by default, so make sure you’re throwing a RuntimeException:

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processOrder(Order order) {
        try {
            // Your business logic here
        } catch (Exception e) {
            throw new RuntimeException("Failed to process order", e);
        }
    }

    Source: Spring Transaction Management

  • Review Propagation Behavior

    If your method isn’t creating a new transaction like you expected, nested @Transactional calls might be muddying the waters. REQUIRES_NEW should always start a fresh transaction, but if the caller isn’t transactional, the behavior can get confusing. Turn on logging to trace what’s happening:

    logging.level.org.springframework.transaction.interceptor=TRACE

    Source: Logging Framework Documentation

Prevention Tips

- Use explicit propagation, monitor transaction boundaries, and test transaction scenarios.
  • Use Explicit Propagation

    Always spell out the propagation behavior in your @Transactional annotations. Defaults like REQUIRED can lead to messy transaction reuse. For example:

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)

    (Trust me, being explicit saves headaches later.)

  • Monitor Transaction Boundaries

    Keep an eye on your transactions with Spring Boot Actuator. Add this to your pom.xml:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    Then expose the transaction endpoints in application.properties:

    management.endpoints.web.exposure.include=health,metrics,beans

    Source: Spring Boot Actuator Documentation

  • Test Transaction Scenarios

    Write integration tests to confirm your transaction behavior. Use @DataJpaTest or @SpringBootTest with a test transaction manager:

    @SpringBootTest
    @Transactional
    public class TransactionalServiceTest {
        @Autowired
        private UserService userService;
    
        @Test
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void testRequiresNewTransaction() {
            userService.createUserWithNewTransaction(new User());
            // Add your assertions here
        }
    }

    Source: Spring Boot Testing Documentation

Edited and fact-checked by the TechFactsHub editorial team.
David Okonkwo
Written by

David Okonkwo holds a PhD in Computer Science and has been reviewing tech products and research tools for over 8 years. He's the person his entire department calls when their software breaks, and he's surprisingly okay with that.

Are Dissertations Printed Double Sided?How Do You Set Up Utilities In A New House?