Spring Transaction Management: Concepts, Configuration, and Best Practices
This article explains the fundamentals of database transactions, the ACID properties, and how Spring provides both declarative and programmatic transaction support through three core interfaces, detailed configuration examples in XML and Java, and a deep dive into transaction attributes such as isolation, propagation, rollback rules, read‑only mode, and timeout.
1. What Is a Transaction
A database transaction is a logical unit of work that must either complete entirely or have no effect at all, ensuring atomicity, consistency, isolation, and durability (ACID).
Typical use case: a money transfer where two updates must succeed or fail together.
2. Transactions in Spring
2.1 Two Usage Styles
Spring supports declarative (via AOP) and programmatic transactions. Declarative is preferred for low coupling; programmatic embeds transaction code directly in business logic.
2.2 Three Core Infrastructure Interfaces
PlatformTransactionManager
TransactionDefinition
TransactionStatus
These interfaces abstract transaction operations across different data sources.
2.2.1 PlatformTransactionManager
Key methods:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition);
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}Implementations include DataSourceTransactionManager , HibernateTransactionManager , and JpaTransactionManager .
2.2.2 TransactionDefinition
Describes transaction attributes (isolation, propagation, timeout, read‑only, rollback rules). Example methods:
int getIsolationLevel();
String getName();
int getPropagationBehavior();
int getTimeout();
bool isReadOnly();Implementations such as DefaultTransactionDefinition are used to configure programmatic transactions.
2.2.3 TransactionStatus
Represents the current transaction state. Important methods:
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();3. Programmatic Transactions
Using PlatformTransactionManager :
@Service
public class TransferService {
@Autowired JdbcTemplate jdbcTemplate;
@Autowired PlatformTransactionManager txManager;
public void transfer() {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = txManager.getTransaction(def);
try {
jdbcTemplate.update("update user set account=account+100 where username='zhangsan'");
int i = 1/0; // simulate error
jdbcTemplate.update("update user set account=account-100 where username='lisi'");
txManager.commit(status);
} catch (DataAccessException e) {
txManager.rollback(status);
}
}
}Using TransactionTemplate :
@Service
public class TransferService {
@Autowired JdbcTemplate jdbcTemplate;
@Autowired TransactionTemplate txTemplate;
public void transfer() {
txTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
jdbcTemplate.update("update user set account=account+100 where username='zhangsan'");
int i = 1/0;
jdbcTemplate.update("update user set account=account-100 where username='lisi'");
} catch (DataAccessException e) {
status.setRollbackOnly();
}
}
});
}
}4. Declarative Transactions
Declarative configuration can be done via XML, Java, or a mix of both.
4.1 XML Configuration
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///spring_tran?serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="insert*" isolation="SERIALIZABLE"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pc1" expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc1"/>
</aop:config>4.2 Java Configuration
@Configuration
@EnableTransactionManagement
public class JavaConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql:///test01?serverTimezone=Asia/Shanghai");
ds.setUsername("root");
ds.setPassword("123");
return ds;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource ds) { return new JdbcTemplate(ds); }
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
@Service
public class UserService {
@Transactional
public void update() { /* business logic */ }
}4.3 Mixed Configuration
Combine XML and Java by importing XML with @ImportResource and defining beans in Java.
5. Transaction Attributes
5.1 Isolation Level
Spring supports MySQL isolation levels (READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE). Default follows the database setting.
Programmatic example:
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);Declarative example:
@Transactional(isolation = Isolation.SERIALIZABLE)
public void update() { /* ... */ }5.2 Propagation Behavior
Spring defines seven propagation types (REQUIRED, SUPPORTS, MANDATORY, REQUIRES_NEW, NOT_SUPPORTED, NEVER, NESTED). Example enum snippet:
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; }
}Declarative configuration example:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void update() { /* ... */ }5.3 Rollback Rules
By default, only unchecked exceptions trigger rollback. Use rollbackFor to include checked exceptions or noRollbackFor to exclude specific unchecked ones.
@Transactional(rollbackFor = IOException.class)
public void handle() { /* ... */ }
@TransactionAdvice ... rollback-for="java.io.IOException" ...5.4 Read‑Only
Mark read‑only transactions for methods that only perform queries to avoid unnecessary write locks.
@Transactional(readOnly = true)
public List
findAll() { return jdbcTemplate.query(...); }5.5 Timeout
Specify the maximum execution time (seconds) after which the transaction is rolled back.
@Transactional(timeout = 10)
public void longRunningTask() { /* ... */ }6. Common Pitfalls
Transactions only apply to public methods.
Self‑invocation bypasses Spring proxies, so internal method calls with @Transactional will not start a transaction.
Prefer placing @Transactional on implementation classes rather than interfaces unless using interface‑based proxies.
7. Summary
Spring provides a comprehensive transaction framework that abstracts the underlying resource, offers flexible configuration, and supports fine‑grained control over isolation, propagation, rollback, read‑only mode, and timeout, enabling developers to write reliable and maintainable data‑access code.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.