Skip to main navigation Skip to main content Skip to page footer

Spring Transaction Management

| Java Spring Boot

Spring provides powerful declarative and programmatic transaction management using the @Transactional annotation or TransactionTemplate. It simplifies managing transactions, ensuring data consistency, flexibility and rollback on errors.

Declarative Transaction Management

Use @EnableTransactionManagement to enable annotation-driven transaction management.

@Configuration
@EnableTransactionManagement
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource("jdbc:mysql://localhost:3306/mydb", "user", "pass");
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

Using @Transactional

Add @Transactional to methods/classes to manage transactions declaratively. The transaction begins when the method is called and in case an exception is being thrown a rollback occurs.

@Service
public class UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void createUser(String name) {
        jdbcTemplate.update("INSERT INTO users (name) VALUES (?)", name);
        // If an exception occurs, the transaction is rolled back.
        if (name == null) throw new IllegalArgumentException("Name cannot be null");
    }
}

Transaction Propagation

Propagation determines how transactions behave when a transactional method calls another transactional method. Common options:

  • REQUIRED (default): Joins an existing transaction or starts a new one.
  • REQUIRES_NEW: Suspends the current transaction and starts a new one.
  • NESTED: Executes in a nested transaction.
  • SUPPORTS: First checks if an active transaction exists, if so the existing transaction will be used, otherwise it is executed non-transactional".
  • MANDATORY: If there is a transaction it will be used, otherwise an exception will be thrown
  • NEVER: In case a transaction is active, an exception will be thrown.
  • NOT_SUPPORTED: If a transaction exists, then it will be removed and afterwards the business logic will be executed.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logTransaction(String message) {
    jdbcTemplate.update("INSERT INTO logs (message) VALUES (?)", message);
}

Rollback Rules

You can configure rollback behavior with @Transactional. By default rollbacks occur on unchecked exceptions (RuntimeException or Error). Checked exceptions like Exception don't trigger a rollback by default.

The rollback behavior can be controlled using rollbackFor and noRollbackFor arguments in the @Transactional annotation.

@Transactional(rollbackFor = Exception.class)
public void saveUser(String name) throws Exception {
    jdbcTemplate.update("INSERT INTO users (name) VALUES (?)", name);
    throw new Exception("Force rollback");
}

@Transactional(noRollbackFor = IllegalArgumentException.class)
public void saveUser(String name) {
    jdbcTemplate.update("INSERT INTO users (name) VALUES (?)", name);
    throw new IllegalArgumentException("No rollback for this exception");
}

Using Transactions in Tests

Spring supports transactions in tests with @Transactional. By default, transactions roll back after the test completes, which is different from the usual behavior.

@SpringBootTest
@Transactional
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testCreateUser() {
        userService.createUser("John");
        // Transaction automatically rolls back after the test.
    }
}

Key Takeaways

  • Use @Transactional for declarative transaction management.
  • Configure propagation based on how nested transactions should behave.
  • Define rollback rules to handle exceptions precisely.
  • Use @Transactional in tests to ensure isolation and automatic rollback.
Back