Search code examples
jakarta-eejboss7.x

Why create JBoss all those transactions


I have a Restfull service, login:

@POST
@Path("login")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Response login(Credentials credentials) {
   // ask database if token exist
   // create token if necessary
}

When the token has to be created, I expect only one transaction, but in the logging I find 4 commits. None of the beans that does the transactions are annotated with @TransactionAttribute.

Why are there 4 commits?

2021-03-03 16:34:17,586 DEBUG [xx.x.LoginResource] (default task-1) Login
2021-03-03 16:34:17,586 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.begin
2021-03-03 16:34:17,591 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.commit
2021-03-03 16:34:17,592 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.begin
2021-03-03 16:34:17,594 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.commit
2021-03-03 16:34:17,595 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.begin
2021-03-03 16:34:17,596 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.begin
2021-03-03 16:34:17,597 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.commit
2021-03-03 16:34:17,610 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.commit

Solution

  • Method-level annotation @TransactionAttribute hints at the intent to use Container-Managed Transactions. As per JAX-RS specification, JAX-RS resources do not constitute a transaction boundary by themself, therefore they are not subject to the Container-Managed Transactions.

    As of JavaEE 6, only EJBs are subject to Container-Managed Transactions. JAX-RS specification explicitly documents the integration with an EJB-enabled container (emphasis is mine):

    In a product that also supports EJB, an implementation MUST support use of stateless and singleton session beans as root resource classes, providers and Application subclasses. JAX-RS annotations MAY be applied to a bean’s local interface or directly to a no-interface bean. If an ExceptionMapper for a EJBException or subclass is not included with an application then exceptions thrown by an EJB resource class or provider method MUST be treated as EJB application exceptions: the embedded cause of the EJBException MUST be unwrapped and processed as described in section 3.3.4.

    In this particular case, it is enough to add the javax.ejb.Stateless annotation at the class level:

    @Path("/")
    @Stateless
    public class LoginResource {
    
        @POST
        @Path("login")
        @TransactionAttribute(TransactionAttributeType.REQUIRED)
        public Response login(Credentials credentials) {
            // ask database if token exist
            // create token if necessary
        }
    
    }
    

    You may also omit method-level @TransactionAttribute(TransactionAttributeType.REQUIRED), as it is a default transaction attribute for EJBs.