Mastering Programmatic Transaction Management in Spring Boot 2.3.9
This guide explains Spring Boot's two programmatic transaction approaches—TransactionTemplate/TransactionalOperator and direct TransactionManager—provides detailed code examples for using TransactionTemplate with return values, rollbacks, property configuration, demonstrates PlatformTransactionManager usage, and shows how to listen to transaction events with @TransactionalEventListener.
Environment
springboot2.3.9.RELEASE
Programmatic Transaction Management Methods
Spring provides two programmatic transaction management methods:
Use
TransactionTemplateor
TransactionalOperatorDirectly create a
TransactionManagerimplementation
Spring officially recommends the
TransactionTemplateapproach.
Preparation
<code>// Entity class
@Entity
@Table(name = "BC_USERS")
@Data
public class Users {
private String username;
private String password;
private Integer status = 0;
}
// DAO
public interface UsersRepository extends JpaRepository<Users, String> {
@Modifying
@Query("update Users u set u.status=?1,u.password='123123' where u.id=?2")
int updateUsers(Integer status, String id);
}
@Mapper
public interface UsersMapper {
int insertUser(Users user);
}
<!-- Mapper.xml -->
<insert id="insertUser" parameterType="com.pack.domain.Users">
insert into bc_users (id, username, password) values (#{id}, #{username}, #{password})
</insert>
</code>TransactionTemplate
1.1 With Return Value
<code>@Service
public class UserService {
@Resource
private TransactionTemplate transactionTemplate;
@Resource
private UsersRepository usersRepository;
public Integer saveUsers(Users users) {
this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus status) {
return usersMapper.insertUser(users);
}
});
return result;
}
}
</code>1.2 Without Return Value
<code>public void saveUsers(Users users) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
usersMapper.insertUser(users);
}
});
}
</code>1.3 Transaction Rollback
<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>1.4 Configuring TransactionTemplate Properties
<code>private TransactionTemplate transactionTemplate;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
this.transactionTemplate.setTimeout(30); // seconds
}
</code>TransactionalOperator
TransactionalOperator is suitable for reactive programming; it is not covered here.
TransactionManager
Two types of transaction managers are available:
PlatformTransactionManager
ReactiveTransactionManager (for reactive programming, not covered)
PlatformTransactionManager Example
<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);
Integer result = null;
try {
result = usersMapper.insertUser(users);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
transactionManager.commit(status);
publisher.publishEvent(new UsersEvent(users));
return result;
}
</code>Transaction Event Listening
Use
@TransactionalEventListenerto listen to events at different transaction phases. This annotation works only with declarative (thread‑bound) transactions managed by
PlatformTransactionManager.
<code>@Component
public class TxListenerComponent {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleUsersAfterCommit(UsersEvent usersEvent) {
Users user = (Users) usersEvent.getSource();
System.out.println("AfterCommit收到事件通知:" + user.getPassword());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void handleUsersAfterCompletion(UsersEvent usersEvent) {
Users user = (Users) usersEvent.getSource();
System.out.println("AfterCompletion收到事件通知:" + user.getPassword());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleUsersAfterRollback(UsersEvent usersEvent) {
Users user = (Users) usersEvent.getSource();
System.out.println("AfterRollback收到事件通知:" + user.getPassword());
}
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleUsersBeforeCommit(UsersEvent usersEvent) {
Users user = (Users) usersEvent.getSource();
System.out.println("BeforeCommit收到事件通知:" + user.getPassword());
}
}
@Resource
private ApplicationEventPublisher publisher;
@Resource
private UsersMapper usersMapper;
public Integer saveUsers(Users users) {
Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus status) {
return usersMapper.insertUser(users);
}
});
publisher.publishEvent(new UsersEvent(users));
return result;
}
</code>Conclusion
Programmatic transaction management is suitable for a small number of transactional operations, such as when a service performs extensive calculations before committing once. For scenarios with many transactional steps, declarative transaction management is more appropriate.
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.