or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aop-interceptors.mddao-support.mddeclarative-transactions.mdexception-hierarchy.mdindex.mdjca-support.mdprogrammatic-transactions.mdreactive-transactions.mdtransaction-events.mdtransaction-managers.mdtransaction-synchronization.md
tile.json

declarative-transactions.mddocs/

Declarative Transaction Management

Declarative transaction management uses annotations to define transaction boundaries and properties. This is the most common and recommended approach for transaction management in Spring applications.

Capabilities

@Transactional Annotation

Describes transaction attributes on methods or classes. When applied to a class, it provides default transaction attributes for all methods in the class. Method-level annotations override class-level settings.

/**
 * Describes transaction attributes on a method or class.
 * When applied at the class level, serves as a default for all methods.
 * When applied at the method level, overrides any class-level settings.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

    /**
     * Alias for transactionManager().
     */
    @AliasFor("transactionManager")
    String value() default "";

    /**
     * Qualifier for the transaction manager to use.
     * Can be a bean name or qualifier value.
     */
    @AliasFor("value")
    String transactionManager() default "";

    /**
     * Labels to associate with the transaction for monitoring/diagnostics.
     */
    String[] label() default {};

    /**
     * Transaction propagation behavior.
     * Default is REQUIRED.
     */
    Propagation propagation() default Propagation.REQUIRED;

    /**
     * Transaction isolation level.
     * Default is DEFAULT (use underlying datastore's default).
     */
    Isolation isolation() default Isolation.DEFAULT;

    /**
     * Transaction timeout in seconds.
     * Default is -1 (use underlying transaction system's default).
     */
    int timeout() default -1;

    /**
     * Transaction timeout as a String expression (supports property placeholders).
     */
    String timeoutString() default "";

    /**
     * Whether transaction is read-only.
     * Default is false.
     */
    boolean readOnly() default false;

    /**
     * Exception types that trigger rollback.
     * By default, only unchecked exceptions cause rollback.
     */
    Class<? extends Throwable>[] rollbackFor() default {};

    /**
     * Exception class name patterns that trigger rollback.
     */
    String[] rollbackForClassName() default {};

    /**
     * Exception types that do NOT trigger rollback.
     */
    Class<? extends Throwable>[] noRollbackFor() default {};

    /**
     * Exception class name patterns that do NOT trigger rollback.
     */
    String[] noRollbackForClassName() default {};
}

Usage Examples:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Isolation;

@Service
public class OrderService {

    // Basic transactional method with default settings
    @Transactional
    public void createOrder(Order order) {
        orderRepository.save(order);
        inventoryService.reserveItems(order.getItems());
    }

    // Read-only transaction for query operations
    @Transactional(readOnly = true)
    public Order getOrder(Long orderId) {
        return orderRepository.findById(orderId);
    }

    // Custom propagation behavior - always create new transaction
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAuditEvent(AuditEvent event) {
        auditRepository.save(event);
    }

    // Custom isolation level for critical operations
    @Transactional(isolation = Isolation.SERIALIZABLE, timeout = 30)
    public void processPayment(Payment payment) {
        paymentRepository.save(payment);
        accountService.debit(payment.getAmount());
    }

    // Rollback on checked exceptions
    @Transactional(rollbackFor = Exception.class)
    public void importData(File dataFile) throws IOException {
        List<Record> records = parser.parse(dataFile);
        recordRepository.saveAll(records);
    }

    // Multiple transaction managers
    @Transactional("orderTransactionManager")
    public void createOrderWithSpecificTxManager(Order order) {
        orderRepository.save(order);
    }

    // Transaction labels for monitoring
    @Transactional(label = {"critical", "payment-processing"})
    public void processHighValuePayment(Payment payment) {
        paymentProcessor.process(payment);
    }
}

@EnableTransactionManagement

Enables Spring's annotation-driven transaction management capability. Must be placed on a @Configuration class.

/**
 * Enables Spring's annotation-driven transaction management capability.
 * Place on @Configuration classes.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

    /**
     * Whether to create class-based (CGLIB) proxies instead of interface-based (JDK) proxies.
     * Default is false (JDK proxies).
     * Set to true if your transactional classes don't implement interfaces.
     */
    boolean proxyTargetClass() default false;

    /**
     * How transactions should be applied: PROXY (default) or ASPECTJ.
     * PROXY uses Spring AOP proxying.
     * ASPECTJ uses load-time or compile-time weaving.
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     * Order for transaction advisor when multiple aspects are applied.
     * Default is LOWEST_PRECEDENCE.
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

    /**
     * Global rollback behavior.
     * RUNTIME_EXCEPTIONS: rollback only on unchecked exceptions (default)
     * ALL_EXCEPTIONS: rollback on all exceptions including checked
     */
    RollbackOn rollbackOn() default RollbackOn.RUNTIME_EXCEPTIONS;
}

Usage Examples:

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

// Basic configuration
@Configuration
@EnableTransactionManagement
public class AppConfig {
    // Define transaction manager bean
}

// With CGLIB proxies for classes without interfaces
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class AppConfig {
    // Configuration beans
}

// With AspectJ weaving for advanced scenarios
@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
public class AppConfig {
    // Configuration beans
}

// With custom advisor order
@Configuration
@EnableTransactionManagement(order = 100)
public class AppConfig {
    // Configuration beans
}

// Rollback on all exceptions
@Configuration
@EnableTransactionManagement(rollbackOn = RollbackOn.ALL_EXCEPTIONS)
public class AppConfig {
    // Configuration beans
}

Propagation Enum

Defines transaction propagation behavior - how transactions relate to each other.

/**
 * Enumeration representing transaction propagation behaviors.
 */
public enum Propagation {

    /**
     * Support a current transaction; create a new one if none exists.
     * This is the default setting.
     */
    REQUIRED,

    /**
     * Support a current transaction; execute non-transactionally if none exists.
     */
    SUPPORTS,

    /**
     * Support a current transaction; throw exception if no transaction exists.
     */
    MANDATORY,

    /**
     * Create a new transaction, suspending the current transaction if one exists.
     */
    REQUIRES_NEW,

    /**
     * Do not support a current transaction; execute non-transactionally.
     * If a transaction exists, suspend it.
     */
    NOT_SUPPORTED,

    /**
     * Do not support a current transaction; throw exception if transaction exists.
     */
    NEVER,

    /**
     * Execute within a nested transaction if a current transaction exists.
     * Behaves like REQUIRED if no transaction exists.
     * Uses savepoints on single transaction with rollback to savepoint on nested failure.
     */
    NESTED;

    /**
     * Returns the TransactionDefinition constant value.
     */
    public int value();
}

Usage Examples:

@Service
public class TransactionPropagationExamples {

    // REQUIRED (default): Join existing or create new
    @Transactional(propagation = Propagation.REQUIRED)
    public void processOrder(Order order) {
        orderRepository.save(order);
        inventoryService.updateStock(order); // Joins this transaction
    }

    // REQUIRES_NEW: Always create independent transaction
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAudit(String message) {
        auditLog.save(message); // Committed independently
    }

    // NESTED: Use savepoint for partial rollback
    @Transactional(propagation = Propagation.NESTED)
    public void processLineItem(LineItem item) {
        // Can rollback just this item without affecting outer transaction
        lineItemRepository.save(item);
    }

    // SUPPORTS: Use transaction if available
    @Transactional(propagation = Propagation.SUPPORTS)
    public Order findOrder(Long id) {
        return orderRepository.findById(id);
    }

    // MANDATORY: Requires existing transaction
    @Transactional(propagation = Propagation.MANDATORY)
    public void validateInTransaction(Order order) {
        // Must be called within existing transaction
        validator.validate(order);
    }

    // NOT_SUPPORTED: Always execute non-transactionally
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void sendEmail(String message) {
        emailService.send(message); // Outside transaction
    }

    // NEVER: Fail if transaction exists
    @Transactional(propagation = Propagation.NEVER)
    public void reportGenerator() {
        // Must never be called within a transaction
        reportService.generate();
    }
}

Isolation Enum

Defines transaction isolation levels controlling visibility of concurrent changes.

/**
 * Enumeration representing transaction isolation levels.
 */
public enum Isolation {

    /**
     * Use the default isolation level of the underlying datastore.
     * All other values are translated to standard JDBC isolation levels.
     */
    DEFAULT,

    /**
     * Lowest isolation level. Permits dirty reads, non-repeatable reads, and phantom reads.
     * Allows reading uncommitted changes from other transactions.
     */
    READ_UNCOMMITTED,

    /**
     * Prevents dirty reads; non-repeatable reads and phantom reads can occur.
     * Guarantees that any data read was committed at the moment it was read.
     */
    READ_COMMITTED,

    /**
     * Prevents dirty reads and non-repeatable reads; phantom reads can occur.
     * Guarantees that if a row is read twice in the same transaction,
     * it will have the same values both times.
     */
    REPEATABLE_READ,

    /**
     * Highest isolation level. Prevents dirty reads, non-repeatable reads, and phantom reads.
     * Guarantees complete isolation from other transactions.
     * Most expensive in terms of performance.
     */
    SERIALIZABLE;

    /**
     * Returns the TransactionDefinition constant value.
     */
    public int value();
}

Usage Examples:

@Service
public class IsolationLevelExamples {

    // Default isolation (database default, usually READ_COMMITTED)
    @Transactional(isolation = Isolation.DEFAULT)
    public void standardOperation() {
        // Uses database's default isolation
    }

    // Read committed for most business operations
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void processPayment(Payment payment) {
        // Prevents reading uncommitted data
        paymentRepository.save(payment);
    }

    // Repeatable read for consistent queries
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public Report generateConsistentReport() {
        // Multiple reads of same data return same values
        List<Order> orders = orderRepository.findAll();
        Statistics stats = calculateStats(orders);
        return new Report(orders, stats);
    }

    // Serializable for critical financial operations
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void transferFunds(Account from, Account to, BigDecimal amount) {
        // Complete isolation, prevents all concurrency anomalies
        from.debit(amount);
        to.credit(amount);
        accountRepository.save(from);
        accountRepository.save(to);
    }

    // Read uncommitted for reporting (accepts risk of dirty reads)
    @Transactional(isolation = Isolation.READ_UNCOMMITTED, readOnly = true)
    public List<Order> generateApproximateReport() {
        // May see uncommitted changes, but faster
        return orderRepository.findAllForReport();
    }
}

RollbackOn Enum

Defines global rollback behavior for all exceptions.

/**
 * Enumeration representing global rollback behavior.
 */
public enum RollbackOn {

    /**
     * Default behavior: rollback only on runtime (unchecked) exceptions.
     * Checked exceptions do not trigger rollback.
     */
    RUNTIME_EXCEPTIONS,

    /**
     * Rollback on all exceptions, including checked exceptions.
     */
    ALL_EXCEPTIONS
}

Usage Example:

@Configuration
@EnableTransactionManagement(rollbackOn = RollbackOn.ALL_EXCEPTIONS)
public class AllExceptionsRollbackConfig {
    // All @Transactional methods will rollback on any exception
}

Transaction Configuration Support

Additional classes supporting declarative transaction configuration.

/**
 * Callback interface for custom transaction manager selection.
 */
public interface TransactionManagementConfigurer {
    /**
     * Returns the default transaction manager bean to use for @Transactional methods.
     */
    TransactionManager annotationDrivenTransactionManager();
}

/**
 * Strategy interface for parsing transaction annotations.
 */
public interface TransactionAnnotationParser {
    /**
     * Determine whether the given class is a candidate for transaction attributes.
     */
    default boolean isCandidateClass(Class<?> targetClass);

    /**
     * Parse the transaction attribute for the given method or class.
     */
    TransactionAttribute parseTransactionAnnotation(AnnotatedElement element);
}

Usage Example:

@Configuration
@EnableTransactionManagement
public class CustomTransactionManagerConfig implements TransactionManagementConfigurer {

    @Bean
    public PlatformTransactionManager primaryTransactionManager() {
        return new DataSourceTransactionManager(primaryDataSource());
    }

    @Bean
    public PlatformTransactionManager secondaryTransactionManager() {
        return new DataSourceTransactionManager(secondaryDataSource());
    }

    @Override
    public TransactionManager annotationDrivenTransactionManager() {
        // Return the default transaction manager for @Transactional
        return primaryTransactionManager();
    }
}

Common Patterns

Service Layer Transactions

@Service
@Transactional
public class UserService {

    // All public methods are transactional by default

    public void createUser(User user) {
        userRepository.save(user);
        eventPublisher.publishEvent(new UserCreatedEvent(user));
    }

    @Transactional(readOnly = true)
    public User getUser(Long id) {
        // Override class-level settings for read operations
        return userRepository.findById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    public void importUsers(File csvFile) throws IOException {
        List<User> users = csvParser.parse(csvFile);
        userRepository.saveAll(users);
    }
}

Transaction Rollback Rules

@Service
public class OrderService {

    // Rollback on specific exception
    @Transactional(rollbackFor = PaymentException.class)
    public void processOrder(Order order) throws PaymentException {
        orderRepository.save(order);
        paymentService.charge(order.getTotal());
    }

    // Don't rollback on specific exception
    @Transactional(noRollbackFor = ValidationException.class)
    public void validateAndSave(Order order) {
        try {
            validator.validate(order);
        } catch (ValidationException e) {
            // Log but don't rollback
            logger.warn("Validation warning", e);
        }
        orderRepository.save(order);
    }

    // Rollback on all exceptions (including checked)
    @Transactional(rollbackFor = Exception.class)
    public void criticalOperation() throws Exception {
        // Any exception causes rollback
        performCriticalWork();
    }
}

Multiple Transaction Managers

@Service
public class MultiDataSourceService {

    @Transactional("orderTransactionManager")
    public void saveOrder(Order order) {
        orderRepository.save(order);
    }

    @Transactional("customerTransactionManager")
    public void saveCustomer(Customer customer) {
        customerRepository.save(customer);
    }
}

Notes

  • @Transactional only works on public methods of Spring-managed beans
  • Self-invocation (calling a transactional method from within the same class) bypasses the proxy and transactions won't be applied
  • For class-level annotations, method-level annotations override the class-level settings
  • By default, only unchecked exceptions (RuntimeException and Error) trigger rollback
  • Read-only transactions can provide performance optimizations in some cases
  • Transaction propagation and isolation settings must be supported by the underlying transaction manager