Distributed Transactions   «Prev  Next»

Lesson 8 Container-Managed Transactions
Objective Understand how the Jakarta EE container manages transactions on behalf of your components.

Container-Managed Transactions

In Jakarta EE, most applications rely on container-managed transactions (CMT). This means the runtime automatically starts, commits, or rolls back a transaction when a business method is invoked. Instead of manually handling begin() and commit(), you simply declare your transaction boundaries, and the container enforces them consistently.

How It Works

When a client calls a business method on a managed component (e.g., a stateless session bean), the container determines the transaction behavior based on annotations. If a transaction is required, the container starts one before invoking your method. When the method finishes, the container commits the transaction, or rolls it back if an exception was thrown.



Jakarta EE Container-Managed Transactions on GlassFish Server
Figure: Jakarta EE container-managed transactions (CMT) on a GlassFish Server.
  • Client → Jakarta EE Component: A client invokes a method on a managed bean.
  • Jakarta EE Component: Bean annotated with @Transactional; transaction boundaries are declared by the developer, enforced by the container.
  • CMT Interceptor: Intercepts the call and applies the defined transaction propagation rules.
  • JTA Transaction Manager: Coordinates enlistment of resources and performs commit or rollback.
  • Database: Executes SQL operations within the managed transaction.

Modern Example (Jakarta EE 10)


  import jakarta.ejb.Stateless;
  import jakarta.transaction.Transactional;
  import jakarta.transaction.Transactional.TxType;

  @Stateless
  public class BankAccountService {

      @Transactional(TxType.REQUIRED)
      public void credit(Long accountId, double amount) {
          BankAccount account = em.find(BankAccount.class, accountId);
          account.setBalance(account.getBalance() + amount);
          // The container will commit or roll back automatically
      }

      @Transactional(TxType.REQUIRES_NEW)
      public void auditTransaction(String message) {
          // Runs in a new transaction independent of the caller
          auditLogRepository.save(new AuditLog(message));
      }
  }
  



Transaction Attributes

The container uses @Transactional (or deployment descriptors for legacy cases) to define how each method participates in a transaction. The main transaction attributes are:

Attribute Behavior
REQUIRED Join the current transaction if one exists; otherwise start a new one (default and most common).
REQUIRES_NEW Always start a new transaction, suspending any existing one.
SUPPORTS Join a transaction if the caller has one; otherwise run without a transaction.
MANDATORY Must run inside an existing transaction; if none exists, an exception is thrown.
NOT_SUPPORTED Run without a transaction. Any existing transaction is suspended during execution.
NEVER Must not run inside a transaction; throws an exception if one exists.

Key Takeaways


SEMrush Software