Mastering Programmatic Transactions in Spring Boot 3.2.5
This tutorial explains how to use Spring Boot's programmatic transaction management—including TransactionTemplate, TransactionCallback, and PlatformTransactionManager—with detailed code examples, configuration tips, and rollback handling to improve data consistency and performance.
Environment: Spring Boot 3.2.5
1. Introduction
Programmatic transactions let developers explicitly control transaction boundaries, start, commit, and rollback, ensuring data consistency. Spring provides two ways: TransactionTemplate/TransactionalOperator or directly implementing TransactionManager. Spring recommends TransactionTemplate for imperative code and TransactionalOperator for reactive code.
2. Practical Examples
2.1 Environment Setup
<code>@Entity
@Table(name="BC_USERS")
public class Users {
private String username;
private String password;
private Integer status = 0;
}
@Mapper
public interface UsersMapper {
int insertUser(Users user);
}
<!-- UsersMapper.xml snippet -->
<insert id="insertUser" parameterType="com.pack.domain.Users">
insert into bc_users (id, username, password) values (#{id}, #{username}, #{password})
</insert>
</code>2.2 TransactionTemplate
TransactionTemplate works like other Spring templates and uses a callback. The execute method receives a TransactionCallback .
<code>@FunctionalInterface
public interface TransactionCallback<T> {
@Nullable
T doInTransaction(TransactionStatus status);
}
</code>For callbacks with no return value, extend TransactionCallbackWithoutResult .
<code>public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
@Override
public final Object doInTransaction(TransactionStatus status) {
doInTransactionWithoutResult(status);
return null;
}
protected abstract void doInTransactionWithoutResult(TransactionStatus status);
}
</code>Example with return value:
<code>@Service
public class UserService {
@Resource
private TransactionTemplate transactionTemplate;
public Integer saveUsers(Users users) {
return transactionTemplate.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus status) {
return usersMapper.insertUser(users);
}
});
}
}
</code>Example without return value:
<code>public void saveUsers(Users users) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
usersMapper.insertUser(users);
}
});
}
</code>Rollback can be triggered via status.setRollbackOnly() inside the callback.
<code>public Users saveUser(Users users) {
return transactionTemplate.execute(new TransactionCallback<Users>() {
@Override
public Users doInTransaction(TransactionStatus status) {
try {
return usersMapper.insertUser(users);
} catch (Exception e) {
status.setRollbackOnly();
}
return null;
}
});
}
</code>TransactionTemplate properties can be customized, e.g., propagation behavior and timeout.
<code>private TransactionTemplate transactionTemplate;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
this.transactionTemplate.setTimeout(30);
}
</code>2.3 TransactionalOperator
Used for reactive programming; omitted here.
2.4 TransactionManager
Two sub‑interfaces: PlatformTransactionManager and ReactiveTransactionManager. Example using PlatformTransactionManager:
<code>private PlatformTransactionManager transactionManager;
private DefaultTransactionDefinition definition;
private TransactionStatus status;
@Resource
private UsersRepository usersRepository;
public UserService3(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
definition = new DefaultTransactionDefinition();
definition.setName("pgName");
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
}
public Integer saveUsers(Users users) {
TransactionStatus status = this.transactionManager.getTransaction(definition);
try {
Integer result = usersMapper.insertUser(users);
transactionManager.commit(status);
return result;
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
</code>The article concludes with a friendly note encouraging readers.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.