Search code examples
jakarta-eetransactionsentitymanager

How does Java EE container control transactions?


I have a question about how transactions are controlled by an EE container. This is pseudo code to give some context to my question. This is not how I code, so please stay on the question and do not evolve the topic into other stuff.

Consider the following two services and related controller. Both services have injected EntityManager and both have methods that need to run within a transaction. One service has a method that does not need any transaction support.

@Stateless
class UserService {
    @PersistenceContext private EntityManager em;

    public void saveUser(User user) {
        em.merge(user);
    }

    public String getFullName(User user) {
        return user.getFirstName() + " " + user.getLastName();
    }
}

@Stateless
class LogService {
    @PersistenceContext private EntityManager em;

    public void logEvent(String eventText) {
        Event event=new Event();
        event.setText(eventText);
        event.setTime(new Date());
        em.persist(event);
    }
}


@Named
class UserController {
    User user;

    @Inject UserService userService;
    @Inject LogService logService;

    public void updateUser(user) { // button posts to this method
        String fullName=userService.getFullName(user);  // 1
        if(fullName.startsWith("X")) return;            // 2
        userService.saveUser(user);                     // 3
        logService.logEvent("Saved user " + fullName);  // 4
    }
}

Now, imagine there's a button that posts a form to userController.updateUser.

My assumption is that the UserController.updateUser() will execute userService.saveUser(user); and logService.logEvent("Saved user " + fullName); within the same transaction. So if the call to logService.logEvent() fails with an SQL Exception, the user entity will not be updated. Also, my assumption is that call to userService.getFullName(user) is not run within any transaction and if we prematurely exit the method when user's name starts with an X, then no transaction is created. But clearly, these are just guesses.

Can someone explain what the Java EE container will do to support UserController.updateUser() method with transaction and what actually triggers the transaction? Also, any further reading you can point me to, would be much appreciated. I've seen some material online but still I'm missing something here and didn't get any help asking around at work, either. So I'm certainly not the only one who's got a gap on this.


Solution

  • In your case 3 independent transactions will be started. Each by one of your @Stateless beans methods. It's because session EJBs have transacional methods with transaction type TransactionAttribute.REQUIRED by default. This means that if a transaction is not already running the new one will be created before method invocation.

    To run all of your session EJBs methods in one transaction you must wrap them in one transaction. In your case you can do this by annotating updateUser(...) method with @Transactional