【问题标题】:Rollback transaction inside managed bean托管 bean 内的回滚事务
【发布时间】:2012-12-10 08:33:23
【问题描述】:

我想不在 EJB 内部而是在 JSF 托管 bean 内部回滚事务。在 EJB 中,我们可以使用 SessionContext.setRollBackOnly(),但我可以在托管 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();
   } 

}

在我的托管 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 ?
      }      
    }    
}

编辑:如何确保如果test1test2test3 之一回滚,其他人也会回滚?

我测试了这段代码,即使accountBean.test2(); 回滚,accountBean.test1(); 也会得到验证。

解决方案是否只能将这 3 个方法嵌套在一个 EJB 方法中?

 @SessionScoped
public class LoginBean implements Serializable{

   public void test(){

      try{
         accountBean.all();
      }catch(CustomException e){
        ...
      }      
    }    
}

【问题讨论】:

    标签: jsf transactions ejb


    【解决方案1】:

    如果抛出未经检查的异常,EJB 容器会自动回滚事务(请注意,JPA 的 PersistenceException 就是这样一个)。你的 CustomException 似乎是一个检查异常。如果将其更改为扩展RuntimeException 如下

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

    或者创建一个新的不是一个选项,那么你需要在rollback属性设置为true的类上设置@ApplicationException注解。

    例如

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

    请注意,具体问题与 JSF 无关。服务层和管理事务完全不在 JSF 的职责范围内。而是由 EJB 负责。从这个角度来看,JSF 应该只是充当“视图”。

    另见:

    【讨论】:

    • 我的CustomException 正在扩展Exception 类,这就是我的事务没有回滚的原因。再次感谢 BalusC,您非常善于教学 :)
    • 是的,创建一个新的 EJB 类/方法,通过单个方法调用执行所有这些服务任务。您知道,事务在默认情况下基本上跨越一个 EJB 方法调用。 JSF 支持 bean 方法不应充当服务。它应该仅通过单个方法调用将模型委托给服务,而不是决定需要执行哪些“子服务”调用。
    • 请注意,一个 EJB 方法可以反过来完美地调用另一个 EJB 类/方法。
    • 是的,我知道,这是因为我没有立即理解为什么在 JSF bean 中调用 EJB 方法没有做同样的事情(就事务而言)。
    【解决方案2】:

    我在这里扮演魔鬼的拥护者,因为 BalusC 的建议是你不应该让你的支持 bean 充当服务,这是绝对正确的。

    但是,纯粹作为技术练习,可以在支持 bean 中启动 JTA 事务,然后以编程方式控制启动和提交或回滚。

    您可以通过@Resource 注入一个UserTransaction 来做到这一点。在调用您的 EJB 方法之前,在此实例上调用 start,在最后一次调用之后提交或回滚。

    同样,这是一个纯理论答案。在实践中,不要这样做,而是让支持 bean 调用 1 个 EJB 方法,该方法在需要时调用其他 EJB bean。

    【讨论】:

    • 不这样做的唯一原因是“纯粹是理论上的答案”这一事实?还是有技术原因(例如性能问题)?
    猜你喜欢
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 2015-03-11
    • 2014-04-30
    • 2020-08-06
    • 1970-01-01
    相关资源
    最近更新 更多