Transaction

Multiple actions performed as a single group

ACID Transactions

AI-generated

  • Atomicity: a transaction commits as one unit or has no effect.
  • Consistency: a committed transaction preserves declared invariants such as constraints; the application still has to encode the correct business rules.
  • Isolation: concurrent transactions interact according to the configured isolation level. Weaker levels allow specific anomalies.
  • Durability: an acknowledged commit survives the failures covered by the database's persistence and replication configuration.

Transaction Types

AI-generated

  • Local: one transactional resource, such as a JDBC connection.
  • Global/distributed: one unit of work coordinates multiple transactional resources, commonly through JTA/XA. This adds failure modes and should not be confused with an ordinary transaction inside one database.

Spring Framework

Consistent programming model across global and local transactions.

Spring Transaction management types

Programmatic

  • Custom code for transaction management.

Example:

public void saveTicket(Ticket ticket) {
  Session session = sessionFactory.getCurrentSession();
  session.getTransaction().begin();   //--
  session.save(ticket);               //  | <=== transaction
  session.getTransaction().commit();  //--
}

Declarative

  • Manages transaction using Spring-specific annotations.
  • Separates transaction management from business code.

Example:

@Transactional
public void scheduleRelease(Ticket ticket, Release release) {
  ticketDao.saveTicket(ticket);
  assignToRelease(ticket, release);
  doOtherStuff(ticket);
}

Manages everything:

  1. Begin
  2. Suspend
  3. Commit
  4. Rollback
  5. Transactional parameters

Transaction Managers

Programmatic Transaction Management:

  1. Transaction template: Similar to Spring templates like JdbcTemplate and other available templates.
  2. Platform transaction manager: Handles transactions across Hibernate, JDBC, JPA, JMS, etc.

Spring Transaction Managers:

  1. Platform transaction manager
  2. JTA
  3. Hibernate
  4. DataSource
  5. JPA

@Transactional annotation

  • Proxy is created to hold transaction management code.
  • Annotation used at the class, interface or method level.
  • Transaction propagation is handled automatically.

NOTE: In Spring boot, it works without configuration.

Spring Configuration

  • JPA Transaction Manager: Registers a transaction manager for us.
  • Additional configuration: Datasource, entity manager, repositories.
  • Spring Data Repositories.

Lifecycle and Scope

Database Transaction

@Transactional defines a single transaction, in the scope of a persistence context.

Persistence Context

  • Defined in JPA
  • Handles a set of entities that contain data to be persisted.

How @Transactional works?

Via proxies!

Transactional call path

AI-generated

Direct call versus transaction proxyA direct invocation bypasses transaction advice; a call through the proxy begins, invokes, and completes the transaction.Direct method call compared with a transaction proxy Without a proxy the caller invokes the application object directly; with a Spring transaction proxy, an interceptor begins a transaction, invokes the target, then commits or rolls back. {"provenance": "AI-generated", "sourceAssets": ["archive/original-images/book/spring/images/without-proxy.png", "archive/original-images/book/spring/images/with-proxy.png"]} @Transactional works when the call crosses the proxy Without proxy Calling code Application object@Transactional method direct call No transaction advice surrounds the invocation. With proxy Calling code Transaction proxyinterceptor Application objectmethod 1 call 2 begin + invoke 3 commit / rollback

Proxy

  • Transaction Interceptor: Intercepts method calls.
  • Platform transaction manager: Handles transactions.

Difference proxies in Spring (JPA?) transaction handling:

  1. Persistence context proxy
  2. Entity manager proxy
  3. Transaction aspect
  4. Transaction manager

Rollbacks

AI-generated

By default, Spring marks a transaction for rollback when an unchecked RuntimeException or an Error escapes the transactional boundary. Checked exceptions do not trigger rollback unless configured.

  • Use @Transactional(rollbackFor=Exception.class) to state otherwise.
  • Use @Transactional(noRollbackFor=SpecificException.class) to avoid rollback on a specific exception.

The usual proxy-based flow is:

  1. Application code throws out of the proxied transactional method.
  2. The transaction interceptor applies rollback rules.
  3. The transaction manager commits or rolls back the resource transaction.

Self-invocation normally bypasses the proxy, and catching an exception inside the method prevents the interceptor from seeing it unless the transaction is marked rollback-only explicitly.

NOTE:

To enable the transaction logging from Spring, set: logging.level.org.springframework.transaction.interceptor=TRACE

Transaction management code

Configuration:

private final TransactionTemplate transactionTemplate;

// constructor
public ReleaseService(PlatformTransactionManager transactionManager) {
  this.transactionTemplate = new TransactionTemplate(transactionManager);
  this.transactionTemplate.setPropagationBehaviorName("PROPAGATION_REQUIRES_NEW");
  this.transactionTemplate.setReadOnly(true);
}

A simple 2 step transaction with the above configuration:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
  public void doInTransactionWithoutResult(TransactionStatus status) {
    try {

    } catch (NoSuchElementException exception) {
      exception.printStackTrace();
      status.setRollbackOnly();
    }
  }
});

Fine-grained control in programmatic transaction management, using platform transaction manager directly.

public Release scheduleRelease(Release release) {
  TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
  TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);

  try {
    createTickets(release);
    assignTicketsToRelease(release.getId(), release.getTickets());

    transactionManager.commit(transactionStatus);
  } catch (RuntimeException e) {
    transactionManager.rollback(transactionStatus);
    throw e;
  }

  return release;
}

Declarative transaction management (vs Programmatic)

  • Manage transaction via configuration.
  • Separate transaction logic from business logic.
  • Easy to maintain.
  • Preferred when a lot of transaction logic.