Transaction management is a crucial means to ensure data consistency and integrity in enterprise-level development. As a widely used framework in the Java ecosystem, Spring’s transaction management module (Spring-Tx) not only provides powerful features but also significantly simplifies developers’ work when handling transactions across different technology stacks. Whether it be programmatic transactions or declarative transactions, Spring meets various scenario requirements with its flexibility and ease of use.
This article will delve into the core technologies and usage methods of the Spring-Tx module from theory to practice, and provide code examples to help you master transaction management more efficiently. It is hoped that through this content, you will gain a comprehensive and in-depth understanding of Spring’s transaction management.
Table of Contents
1、Introduction to Spring-Tx Module
1.1、Overview of Spring-Tx Module
The Spring Tx module is a component of the Spring framework responsible for handling transaction management, where TX stands for Transaction Management.
The design goal of the Spring Tx module is to simplify, unify, and make transaction management more flexible in applications. It provides a consistent programming model for managing transactions regardless of whether it’s in a traditional JDBC environment or an ORM (such as Hibernate) environment.
1.2、Dependencies of Spring-Tx Module
The Spring Tx module depends on two other modules: the Spring-Beans module and the Spring-Core module.
The Spring Beans module defines Spring Bean and implements the core functionality of IOC (Inversion of Control). The Spring-Core module, on the other hand, is the foundation of the Spring framework, providing essential functionalities required for its operation.
It’s important to note that while the Spring Tx module achieves transaction management based on the principles of Spring AOP (Aspect-Oriented Programming), it does not depend on specific AOP implementation modules of Spring. Instead, it accomplishes this through its own mechanisms.
1.3 The Function of Spring-Tx Module
The Spring-Tx module provides developers with a set of efficient and flexible transaction management mechanisms, applicable to various persistence technologies and transaction scenarios.
2 Transaction Overview
In general, a transaction is a logical unit consisting of a finite set of operations. The purpose of transaction operations is twofold: data consistency and operation isolation. Data consistency refers to ensuring that all operations within the transaction are successfully completed when the transaction is committed, and the changes are permanently saved; in case of a rollback, the system should revert to its previous state before the transaction was executed. Operation isolation ensures that multiple concurrently executing transactions operate independently without affecting each other.
Transactions are a broad concept, encompassing not just databases but also resources like message queues and file systems. However, typically, when we mention transactions, we primarily refer to “database transactions.”
3 Spring Transactions
Spring transactions can be implemented in two ways: programmatic transactions and declarative transactions.
- Programmatic transactions involve managing the transaction by writing code to handle commit, rollback, and define the boundaries. This means developers must explicitly call methods to start, commit, and rollback transactions within their code.
- Declarative transactions are managed through configuration, allowing you to use annotations or XML configurations to define transaction boundaries and properties without needing to write explicit transaction management code.
3.1 Spring Programmatic Transactions
Programmatic transactions involve using Spring’s transaction-related classes in a hard-coded manner to control the flow of transactions. There are primarily two approaches:
- Method 1: Controlling transactions via PlatformTransactionManager
- Method 2: Controlling transactions via TransactionTemplate
3.1.1 Controlling Transactions with PlatformTransactionManager
This is the most fundamental approach, involving more code as other methods are built upon it. It requires manual management of transaction definition, starting, committing, and rolling back. While offering high flexibility, it can be quite verbose in terms of code.
Example code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; public class TransactionService1 { private final PlatformTransactionManager transactionManager; public TransactionService1(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public void executeTransaction() { // Define the transaction TransactionDefinition def = new DefaultTransactionDefinition(); // Begin the transaction TransactionStatus status = transactionManager.getTransaction(def); try { // Business logic implementation performBusinessLogic(); // Commit the transaction transactionManager.commit(status); } catch (Exception e) { // On exception, roll back the transaction transactionManager.rollback(status); throw e; } } private void performBusinessLogic() { // Simulate business logic System.out.println(“Executing business logic…”); // Simulate an error if (true) { throw new RuntimeException(“Error occurred”); } } } |
Strengths and weaknesses:
- Strengths: High flexibility, suitable for scenarios requiring special control over transactions.
- Weaknesses: More code required, increases complexity, prone to missing rollback or commit operations.
3.1.2、Controlling Transactions via TransactionTemplate
TransactionTemplate is a transaction management utility class provided by Spring. It encapsulates the logic for starting, committing, and rolling back transactions, simplifying code. Developers only need to focus on implementing business logic.
Example code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; public class TransactionService2 { private final TransactionTemplate transactionTemplate; public TransactionService2(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } public void executeTransaction() { // Execute transactions using TransactionTemplate transactionTemplate.execute((TransactionCallback<Void>) status -> { // Business logic implementation performBusinessLogic(); return null; // Return result, adjust Void type if needed for return value }); } private void performBusinessLogic() { // Simulate business logic System.out.println(“Executing business logic…”); // Simulate exception if (true) { throw new RuntimeException(“Error occurred”); } } } |
Advantages and Disadvantages:
- Advantages: Simple code, developers do not need to manually manage transaction submission and rollback.
- Disadvantages: Flexibility is slightly lower than directly using PlatformTransactionManager.
3.2、Declarative Transactions in Spring
3.2.1、Declaring Transactions
Declarative transactions refer to controlling transaction submission and rollback using annotations or XML configuration. Developers only need to add configurations, and the specific implementation of transactions is handled by third-party frameworks, avoiding direct transaction operations.
Spring provides the @EnableTransactionManagement annotation on configuration classes (main application classes) to enable support for transactions. At this point, Spring will automatically scan classes and methods annotated with @Transactional. This annotation is equivalent to the XML configuration approach’s <tx:annotation–driven />. By setting the mode property, you can decide whether to use Spring proxies or ASPECTJ extensions.
1 2 3 4 5 6 7 8 9 |
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; // Proxy mode int order() default Ordered.LOWEST_PRECEDENCE; // LOWEST_PRECEDENCE lowest priority, so it runs at the outermost layer of the execution chain. Since custom AOP interceptors have higher priority than transactions, they are nested inside, closer to business code. } |
3.2.2、Using the @Transactional Annotation
The @Transactional annotation can be applied to classes and methods. When declared on a class, this annotation defaults to applying to all methods of the class and its subclasses; however, it only takes effect for public methods. For parent class methods to include annotations of the same level, separate declarations are required.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor(“transactionManager”) String value() default “”; // Used to determine the target transaction manager @AliasFor(“value”) String transactionManager() default “”; // Transaction propagation, default is Propagation.REQUIRED Propagation propagation() default Propagation.REQUIRED; // Transaction isolation level, default is Isolation.DEFAULT Isolation isolation() default Isolation.DEFAULT; // Transaction timeout, default is -1 int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; // Indicates whether the transaction is read-only, default is false, just a hint boolean readOnly() default false; // Identifies exception types that can trigger transaction rollback, defaults to RuntimeException and Error, excluding checked exceptions. Class<? extends Throwable>[] rollbackFor() default {}; // Specifies which exceptions should not cause transaction rollback Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {}; String[] rollbackForClassName() default {}; } |
Among these, the isolation and timeout attributes only take effect for newly started transactions and are specifically designed for use with Propagation.REQUIRED and Propagation.REQUIRES_NEW.
3.2.3、Transaction Propagation – Propagation
Propagation defines the propagation of transactions, with a total of 7 levels.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public enum Propagation { REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED), SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS), MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY), REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), NEVER(TransactionDefinition.PROPAGATION_NEVER), NESTED(TransactionDefinition.PROPAGATION_NESTED); private final int value; Propagation(int value) { this.value = value; } public int value() { return this.value; } } |
-
REQUIRED :Use the current transaction, if there is no current transaction, create a new one; sub-methods must run within a transaction. If a transaction already exists, join it as part of the whole.
-
SUPPORTS :If a current transaction exists, use it; if not, do not use a transaction. Often used for queries.
-
MANDATORY:The propagation attribute mandates that a transaction must exist. If none exists, an exception is thrown.
-
REQUIRES_NEW:If a current transaction exists, suspend it and create a new one; if not, behave like REQUIRED.
-
NOT_SUPPORTED:If a current transaction exists, suspend it and run without a transaction.
-
NEVER:Throw an exception if a current transaction exists.
-
NESTED:If a current transaction exists, start a nested (sub-)transaction; if not, behave like REQUIRED. However, if the main transaction commits, it carries the sub-transactions to commit. If the main transaction rolls back, the sub-transactions roll back as well. Conversely, if a sub-transaction throws an exception, the parent can choose to roll back or not (try-catch).
3.2.4、Transaction Isolation Levels – Isolation
The isolation level defines how transactions are isolated from each other, with five options available.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public enum Isolation { DEFAULT(TransactionDefinition.ISOLATION_DEFAULT), READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED), READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED), REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ), SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE); private final int value; Isolation(int value) { this.value = value; } public int value() { return this.value; } } |
Spring transaction isolation levels total five types, with the setting of isolation levels depending on whether the current database supports it.
- DEFAULT: Uses the default isolation level of the current database. For example, Oracle uses READ_COMMITED, MySQL uses READ_REPEATED.
- READ_UNCOMMITED: Can lead to dirty reads, non-repeatable reads, and phantom reads.
- READ_COMMITTED: Prevents dirty reads but can still result in non-repeatable reads and phantom reads.
- REPEATABLE_READ: Prevents both dirty reads and non-repeatable reads but can lead to phantom reads.
- SERIALIZABLE: Transactions are executed sequentially at this level, preventing the aforementioned issues, though with higher overhead.
Postscript
Transaction management plays a critical role in modern applications, especially with the increasing prevalence of distributed systems and microservices architectures. Effectively managing data consistency has become a challenge for every developer. The Spring-Tx module offers a one-stop solution with its simple, elegant, and powerful features.
Through this article, I trust you have gained an understanding of the basic principles, configuration methods, and specific usage of both programmatic and declarative transactions in Spring-Tx. In practical projects, choosing appropriate transaction management approaches and configuring transaction properties effectively can significantly enhance system stability and reliability.
I look forward to seeing you leverage the Spring-Tx module flexibly in your future development efforts, delivering higher efficiency and better performance for your projects.
Leave a Reply
You must be logged in to post a comment.