SoFunction
Updated on 2025-04-06

SpringBoot Programming Transaction Usage and Two Implementations

1. Introduction

Programmatic transaction management is to manage transactions by writing code, which provides finer granular transaction control over declarative transactions (@Transactional annotation). In SpringBoot, there are two main implementation methods:

  • Use TransactionTemplate
  • Use TransactionManager directly

2. TransactionTemplate method

TransactionTemplate is the simplest way to implement programming transactions. It encapsulates the underlying transaction API and is more convenient to use.

2.1 Basic configuration

@Configuration
public class TransactionConfig {
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Bean
    public TransactionTemplate transactionTemplate() {
        TransactionTemplate template = new TransactionTemplate();
        (transactionManager);
        // Set the default transaction propagation behavior        (TransactionDefinition.PROPAGATION_REQUIRED);
        // Set the default transaction isolation level        (TransactionDefinition.ISOLATION_DEFAULT);
        // Set the default timeout        (30);
        return template;
    }
}

2.2 Basic usage examples

@Service
@Slf4j
public class UserService {
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private UserRepository userRepository;
    public User createUser(User user) {
        // Use the execute method to perform transaction operations with return values        return (status -> {
            try {
                User savedUser = (user);
                // Simulate other operations                updateUserProfile(savedUser);
                return savedUser;
            } catch (Exception e) {
                // Manually mark transaction rollback                ();
                ("Creating user failed", e);
                throw new RuntimeException("Creating user failed", e);
            }
        });
    }
    public void batchCreateUsers(List<User> users) {
        // Use the executeWithoutResult method to perform transaction operations without return value        (status -> {
            try {
                for (User user : users) {
                    (user);
                }
            } catch (Exception e) {
                ();
                ("Batch creation of user failed", e);
                throw new RuntimeException("Batch creation of user failed", e);
            }
        });
    }
}

3. TransactionManager method

Directly using TransactionManager provides finer granular transaction control, but is relatively complex to use.

3.1 Basic usage examples

@Service
@Slf4j
public class OrderService {
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Autowired
    private OrderRepository orderRepository;
    public Order createOrder(Order order) {
        // Define transaction properties        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        (TransactionDefinition.PROPAGATION_REQUIRED);
        (TransactionDefinition.ISOLATION_READ_COMMITTED);
        (30);
        // Get transaction status        TransactionStatus status = (def);
        try {
            // Execute business logic            Order savedOrder = (order);
            // Other operations related to handling orders            processOrderDetails(savedOrder);
            // Submit transaction            (status);
            return savedOrder;
        } catch (Exception e) {
            // Roll back the transaction            (status);
            ("Create order failed", e);
            throw new RuntimeException("Create order failed", e);
        }
    }
}

3.2 Nested Transaction Example

@Service
@Slf4j
public class PaymentService {
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Autowired
    private PaymentRepository paymentRepository;
    public void processPayment(Payment payment) {
        // External transaction definition        DefaultTransactionDefinition outerDef = new DefaultTransactionDefinition();
        (TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus outerStatus = (outerDef);
        try {
            // External transaction operations            (payment);
            // Internal transaction definition            DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
            (TransactionDefinition.PROPAGATION_NESTED);
            TransactionStatus innerStatus = (innerDef);
            try {
                // Perform internal transaction operations                processPaymentDetails(payment);
                (innerStatus);
            } catch (Exception e) {
                // Roll back internal transactions                (innerStatus);
                ("Payment details processing failed", e);
                throw e;
            }
            // Submit external transactions            (outerStatus);
        } catch (Exception e) {
            // Roll back external transactions            (outerStatus);
            ("Payment processing failed", e);
            throw new RuntimeException("Payment processing failed", e);
        }
    }
}

4. Transaction communication behavior

In a programming transaction, we can accurately control the propagation behavior of the transaction:

@Service
public class TransactionPropagationExample {
    @Autowired
    private TransactionTemplate transactionTemplate;
    public void demonstratePropagation() {
        // REQUIRED propagation behavior        TransactionTemplate requiredTemplate = new TransactionTemplate(transactionTemplate);
        (TransactionDefinition.PROPAGATION_REQUIRED);
        // REQUIRES_NEW Propagation Behavior        TransactionTemplate requiresNewTemplate = new TransactionTemplate(transactionTemplate);
        (TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        //Nesting different propagation behaviors        (outerStatus -> {
            // External transaction logic            (innerStatus -> {
                // Internal transaction logic (new transaction)                return null;
            });
            return null;
        });
    }
}

5. Transaction isolation level

Examples show how to set different transaction isolation levels:

@Service
public class TransactionIsolationExample {
    @Autowired
    private PlatformTransactionManager transactionManager;
    public void demonstrateIsolation() {
        // Read the submitted isolation level        DefaultTransactionDefinition readCommittedDef = new DefaultTransactionDefinition();
        (TransactionDefinition.ISOLATION_READ_COMMITTED);
        TransactionStatus readCommittedStatus = (readCommittedDef);
        try {
            // Business logic            (readCommittedStatus);
        } catch (Exception e) {
            (readCommittedStatus);
            throw e;
        }
        // Repeatable isolation level        DefaultTransactionDefinition repeatableReadDef = new DefaultTransactionDefinition();
        (TransactionDefinition.ISOLATION_REPEATABLE_READ);
        // ... Similar transaction processing logic    }
}

6. Best Practices

6.1 Transaction template encapsulation

Create a common transaction template:

@Component
@Slf4j
public class TransactionHelper {
    @Autowired
    private TransactionTemplate transactionTemplate;
    public <T> T executeInTransaction(TransactionCallback<T> action) {
        try {
            return (action);
        } catch (Exception e) {
            ("Transaction execution failed", e);
            throw new RuntimeException("Transaction execution failed", e);
        }
    }
    public void executeInTransactionWithoutResult(Consumer<TransactionStatus> action) {
        try {
            (action);
        } catch (Exception e) {
            ("Transaction execution failed", e);
            throw new RuntimeException("Transaction execution failed", e);
        }
    }
}
// Use example@Service
public class BusinessService {
    @Autowired
    private TransactionHelper transactionHelper;
    public void doBusiness() {
        (status -> {
            // Business logic        });
    }
}

7. FAQs and Solutions

7.1 Transaction timeout processing

@Service
public class TimeoutExample {
    @Autowired
    private TransactionTemplate transactionTemplate;
    public void handleTimeout() {
        TransactionTemplate timeoutTemplate = new TransactionTemplate(transactionTemplate);
        (5); // Set 5 seconds timeout        try {
            (status -> {
                // Business logic that may timeout                return null;
            });
        } catch (TransactionTimedOutException e) {
            // Handle timeout exception            ("Transaction execution timeout", e);
            throw new RuntimeException("Transaction execution timeout", e);
        }
    }
}

7.2 Exception handling best practices

@Service
public class ExceptionHandlingExample {
    @Autowired
    private TransactionTemplate transactionTemplate;
    public void handleExceptions() {
        try {
            (status -> {
                try {
                    // Business logic                    return null;
                } catch (BusinessException e) {
                    // Business exception, mark rollback                    ();
                    throw e;
                } catch (Exception e) {
                    // Other exceptions, mark rollback                    ();
                    throw new RuntimeException("Unexpected Error", e);
                }
            });
        } catch (Exception e) {
            // Unified exception handling            handleException(e);
        }
    }
    private void handleException(Exception e) {
        if (e instanceof BusinessException) {
            // Handle business exceptions            ("Business exception: {}", ());
        } else {
            // Handle system exceptions            ("System Exception", e);
        }
        throw e;
    }
}

While programming transactions provide finer granular control, in most cases declarative transactions (@Transactional) may be a better choice. Use of programmatic transactions is only considered when particularly fine transaction control is required.

This is the end of this article about the use of SpringBoot programming transactions. For more related SpringBoot programming transactions, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!