Spring Transaction Management
The relationship between Spring transaction management related interfaces is as follows:

Transaction management overview
Spring provides a unified transactional programming model for different data access technologies such as JDBC, JPA, Hibernate, and JTA. Business code is mainly oriented towards Spring’s transaction abstraction, while specific commit, rollback, and resource management are completed by the corresponding transaction manager.
The core interface is PlatformTransactionManager:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}getTransaction() Obtain the current transaction status according to the transaction definition;commit() and rollback() Responsible for submitting and rolling back respectively.
Common transaction managers
JDBC transaction
Use JDBC or JdbcTemplate When, usually used DataSourceTransactionManager。
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>It obtains JDBC from the same data source Connection Manage transactions and ultimately invoke the connected commit() or rollback()。
JPA Affairs
When using JPA, you usually use JpaTransactionManager。
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>JpaTransactionManager With JPA EntityManagerFactory、EntityManager Collaborate on managing affairs.
Hibernate transactions
Use native Hibernate directly SessionFactory When you can use HibernateTransactionManager。If the project is implemented using Hibernate through JPA, it should be preferred JpaTransactionManager。
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>JTA transaction
When a business operation needs to coordinate multiple transactional resources, you can use JTA and JtaTransactionManager。For example, a transaction involves multiple databases or databases and messaging systems simultaneously.
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>The specific configuration of JTA depends on the application server or the transaction coordinator used. You cannot rely on a fixed Bean configuration to adapt to all environments.
transaction attribute
TransactionDefinition Used to describe the transaction policy, which mainly includes propagation behavior, isolation level, timeout time, read-only flag, and transaction name.

public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}transaction communication behavior
Propagation behavior determines whether a method with a transaction should join an existing transaction, create a new transaction, or prohibit the transaction when it is called by another transaction method.
| communication behavior | meaning |
|---|---|
REQUIRED | Default value. If there is a transaction, join it, and if there is no transaction, create a new transaction. |
SUPPORTS | If there is a transaction, join, and if there is no transaction, it will run in a non-transactional manner. |
MANDATORY | A transaction must exist, otherwise an exception is thrown. |
REQUIRES_NEW | Always create a new transaction; if you already have a transaction, suspend the outer transaction. |
NOT_SUPPORTED | Runs non-transactionally; if there is a transaction, suspends the transaction. |
NEVER | Must be run non-transactionally; if a transaction exists, an exception is thrown. |
NESTED | Use savepoints to form nested scopes when there is a transaction; behave similarly when there is no transaction REQUIRED。 |
REQUIRED
Multiple methods join the same physical transaction, where any participant marks the transaction as rollback only, and the entire transaction is rolled back when it is finally committed.
@Transactional(propagation = Propagation.REQUIRED)
public void saveOrder() {
// 业务逻辑
}REQUIRES_NEW
Inner methods use independent transactions, and outer transactions are suspended during the execution of the inner transaction. After an inner transaction commits, even if the outer transaction subsequently rolls back, the inner committed content usually does not roll back.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveAuditLog() {
// 独立保存审计日志
}NESTED
NESTED Typically based on JDBC savepoint implementations in the same physical transaction. The inner scope can be rolled back to the savepoint, but it cannot be finally committed separately from the outer transaction like an independent transaction; when the outer transaction is rolled back, the nested scope will also be rolled back.
This propagation behavior relies on the transaction manager and underlying resource support for savepoints, and is common in JDBC resource transactions.
transaction isolation level
Isolation levels are used to control data visibility between concurrent transactions.
Common questions about concurrent transactions
- Dirty read: Read data that has not yet been committed by other transactions.
- Non-repeated read: Reading the same row twice within the same transaction results in different values, usually caused by updates and committing by other transactions.
- Magic read: When querying twice in the same transaction under the same conditions, the number of rows in the result set changes, usually caused by the insertion or deletion of other transactions and committing.
Spring isolation level
| isolation level | meaning |
|---|---|
DEFAULT | Use the database default isolation level. |
READ_UNCOMMITTED | Uncommitted data is allowed to be read, and dirty reads, non-repeatable reads, and phantom reads may occur. |
READ_COMMITTED | Only committed data can be read to avoid dirty reading. |
REPEATABLE_READ | Consistently reading of read rows within the same transaction avoids dirty and non-repeatable reads. |
SERIALIZABLE | Transactions are executed approximately serially, with the highest isolation, but generally the lowest concurrency performance. |
Different databases have different locking mechanisms and multi-version concurrency control implementations, so the isolation level of the same name may differ in specific details.
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateAccount() {
// 业务逻辑
}read-only transactions
The read-only flag indicates that the transaction mainly performs query operations, and the transaction manager and database can optimize accordingly.
@Transactional(readOnly = true)
public User queryById(Long id) {
return userMapper.selectById(id);
}readOnly = true This is usually an optimization tip and should not be regarded as an absolute database write security limit. Whether writes are actually disabled depends on the transaction manager and database implementation.
transaction timeout
Transaction timeouts are used to limit the maximum time a transaction is allowed to execute. After a timeout, transactions are usually marked as rolling back.
@Transactional(timeout = 10)
public void importData() {
// 业务逻辑
}Avoid performing long network calls, file processing, or human waits during transactions, otherwise it may consume database connection and lock resources for a long time.
Rollback rule
Spring declarative transactions default when thrown RuntimeException or Error When rolled back; for ordinary checked exceptions, no rolled back by default.
@Transactional(rollbackFor = Exception.class)
public void transfer() throws Exception {
// 发生受检异常时也回滚
}can also noRollbackFor Specifies that certain exceptions do not trigger rollback.
@Transactional(noRollbackFor = BusinessWarningException.class)
public void execute() {
// 业务逻辑
}Rollback rules should be set according to business semantics, and it is not recommended to silently process exceptions after indiscriminately capturing exceptions. If an exception is caught internally by a method and is no longer thrown, the transaction interceptor is usually unaware of the exception and will not automatically roll back as the exception.
transaction state
TransactionStatus Represents the running state of the current transaction and provides capabilities such as savepoints and rollback-only flags.
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
boolean hasSavepoint();
void flush();
}Common state methods include:
isNewTransaction(): Whether a new transaction has been created for the current call.hasSavepoint(): Whether you hold a save point.setRollbackOnly(): Mark the transaction as rollback only.isRollbackOnly(): Whether the transaction has been marked for rollback.isCompleted(): Whether the transaction has been completed.
The specific method of the interface will evolve with Spring versions, and its use should be based on the API in the current project.
programmatic transaction
Programmatic transactions clearly control transaction boundaries by business code, which is suitable for scenarios where the transaction scope requires dynamic determination or fine control. Its shortcoming is that transaction code will enter business logic and is highly intrusive.
use TransactionTemplate
TransactionTemplate Is one of the recommended programmatic transactions.
@Service
public class UserService {
private final TransactionTemplate transactionTemplate;
private final UserRepository userRepository;
public UserService(
TransactionTemplate transactionTemplate,
UserRepository userRepository) {
this.transactionTemplate = transactionTemplate;
this.userRepository = userRepository;
}
public Boolean save(User user) {
return transactionTemplate.execute(status -> {
try {
userRepository.insert(user);
return true;
} catch (RuntimeException e) {
status.setRollbackOnly();
throw e;
}
});
}
}If the callback throws a run-time exception, the transaction template is rolled back according to the rules. An explicit call to the exception is needed only if you need to convert it to a normal return value setRollbackOnly()。
used directly PlatformTransactionManager
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(definition);
try {
userRepository.insert(user);
transactionManager.commit(status);
} catch (RuntimeException e) {
transactionManager.rollback(status);
throw e;
}Operating the transaction manager directly is more flexible, but you need to ensure that the commit, rollback, and exception propagation logic are correct.
declarative transaction
Declarative transactions are based on Spring AOP, applying transaction logic to target methods through configuration or annotations, and business code does not require manual commit and rollback.
XML configuration method
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="query*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="servicePointcut"
expression="execution(* com.example.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
</aop:config>Needs to be declared in the root element tx and aop Namespace.
annotation method
Enable transaction annotations first:
<tx:annotation-driven transaction-manager="transactionManager"/>You can also use Java configuration:
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}Use on business classes or methods @Transactional:
@Service
public class UserService {
private final UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
@Transactional(rollbackFor = Exception.class)
public void save(User user) throws Exception {
userDao.insert(user);
}
}Annotations on classes serve as the default transaction configuration for methods of this class; annotations on methods can override class-level configuration.
@Transactional Common failure scenarios
Same kind of internal call
In default proxy mode, a method passes the this Calls another one of its kind @Transactional Method, the call does not go through the Spring proxy, and the independent transaction configuration of the inner method usually does not take effect.
@Service
public class OrderService {
public void createOrder() {
// 这是同类内部调用,不会经过代理对象。
saveOrder();
}
@Transactional
public void saveOrder() {
// 数据库操作
}
}Generally, methods that require independent transaction boundaries should be split into another Spring Bean.
Method is not proxyable
In common proxy patterns, transactions should usually be applied to exposed instance methods that can be invoked by the proxy.private Methods, static methods, and object-created methods do not take effect as normal Spring Bean proxies.
The object is not a Spring Bean
by new Manually created objects are not managed by the Spring container and @Transactional Comments will not take effect automatically.
Exception caught
@Transactional
public void save() {
try {
userDao.insert();
} catch (Exception e) {
// 异常被吞掉后,事务拦截器无法按该异常自动回滚。
}
}Exceptions should be re-thrown or called based on business needs TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。
Exception type mismatch
By default, exceptions under inspection do not trigger rollback. When you need to roll back, you should pass the rollbackFor Clear configuration.
use recommendations
- Transactions are usually placed at the Service layer rather than the Controller layer.
- A transaction covers only database operations that must be consistent.
- Avoid long-term remote calls during transactions.
- The query method can be set to read-only transactions.
- Choose communication behavior based on business semantics, and don’t configure all methods to
REQUIRES_NEW。 - When you convert exceptions, you should preserve the original exception information and ensure that the rollback rules are still in effect.
If you enjoyed this, leave a comment~