3

I would like to rollback transaction not inside EJB but inside JSF managed bean. Inside EJB we can use SessionContext.setRollBackOnly() but what can I use in managed bean ?

@Stateless
@Local(AccountLocal.class)
public class AccountBean implements AccountLocal {

   public void test1() throws CustomException(){
      ...
   } 

   public void test2() throws CustomException(){
      ...
      throw new CustomException();
   }   

   public void test3() throws CustomException(){
      ...
   }

   public void all() throws CustomException(){
       test1();
       test2();
       test3();
   } 

}

In my managed bean :

@SessionScoped
public class LoginBean implements Serializable{

   public void test(){

      try{
         accountBean.test1();
         accountBean.test2();
         accountBean.test3();
      }catch(CustomException e){
         // WHAT HERE TO ROLLBACK TRANSACTION ?
      }      
    }    
}

EDIT : How can I ensure that if one of the test1, test2 or test3 rolls back, others will roll back too ?

I tested this code and accountBean.test1(); is validated even if accountBean.test2(); rolls back.

Could the solution be only to nest this 3 methods inside one EJB method ?

 @SessionScoped
public class LoginBean implements Serializable{

   public void test(){

      try{
         accountBean.all();
      }catch(CustomException e){
        ...
      }      
    }    
}
Roman C
  • 49,761
  • 33
  • 66
  • 176
Olivier J.
  • 3,115
  • 11
  • 48
  • 71

2 Answers2

5

Transactions are automatically rolled back by the EJB container if an unchecked exception is thrown (note that JPA's PersistenceException is such one). Your CustomException seems to be a checked exception. If changing it to extend RuntimeException as follows

public class CustomException extends RuntimeException {
    // ...
}

or creating a new one is not an option, then you need to set the @ApplicationException annotation on the class with the rollback attribute set to true.

E.g.

@ApplicationException(rollback=true)
public class CustomException extends Exception {
    // ...
}

Please note that the concrete problem has nothing to do with JSF. The service layer and managing transactions is completely outside the responsibility of JSF. It's the responsibility of EJB instead. JSF should merely act as "view" in this perspective.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • My `CustomException` is extending `Exception` class so that's why my transaction wasn't rolled back. Many thanks again BalusC you are very pedagogical :) – Olivier J. Dec 23 '12 at 17:09
  • 2
    Yes, create a new EJB class/method performing all those service tasks by a single method call. You know, the transaction spans by default basically one EJB method call. JSF backing bean method should not act as service. It should merely delegate the model to the service by a single method call and not decide which "subservice" calls needs to be performed. – BalusC Dec 23 '12 at 19:20
  • Note that an EJB method can in turn perfectly fine call another EJB classes/methods. – BalusC Dec 23 '12 at 19:39
  • Yes I know and this is because I did not understand immediately why calling EJB methods inside JSF bean did not do the same (in terms of transactions). – Olivier J. Dec 23 '12 at 19:43
1

I'm playing the Devil's advocate here, since BalusC's advice that you should not let your backing beans act as services is absolutely true.

But, purely as a technical excersise, it -is- possible to start a JTA transaction in a backing bean and then control start and commit or rollback programmatically.

You can do this by injecting a UserTransaction via @Resource. Prior to calling your EJB methods, call start on this instance, and after the last call either commit or rollback.

Again, this is a purely theoretical answer. In practice, don't do this and let the backing bean call 1 EJB method that calls out to other EJB beans if needed.

Mike Braun
  • 3,729
  • 17
  • 15
  • The only reason to not do something like this is the fact that "is a purely theoretical answer"? Or there are technical reasons (e.g., performance issues)? – Cold May 14 '19 at 10:22