Backend Development 7 min read

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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Programmatic Transactions in Spring Boot 3.2.5

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.

JavaSpring BootProgrammatic TransactionTransactionalOperatorTransactionTemplate
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.