2014-01-26 93 views
0

我正在实现JEE7 Web应用程序。在我的工作中,我发现处理自定义异常时遇到问题。投掷应用程序异常导致TransactionalException

我编辑了我的账户属性以拥有非唯一的登录字段。然后我调用AccountEditBean#editAccount()来运行编辑过程。当进程来到AccountFacade#edit()我可以看到(在调试中)PersistenceException被捕获,我的自定义NonUniqueException被抛出。问题是,该异常不会传播出外观类,并且不会在AccountEditBean中处理。而不是TransactionalException发生throw后右: NonUniqueException延伸BaseApplicationException,其被标记为@ApplicationException(rollback=true)

WARNING: EJB5184:A system exception occurred during an invocation on 
EJB ADMEndpoint, method: public void 
pl.rozart.greatidea.adm.endpoints.ADMEndpoint.editAccount(pl.rozart.greatidea.entities.Account) 
throws pl.rozart.greatidea.exceptions.BaseApplicationException 
WARNING: javax.transaction.TransactionalException: Managed bean with 
Transactional annotation and TxType of REQUIRES_NEW encountered 
exception during commit javax.transaction.RollbackException: 
Transaction marked for rollback. 

的附加信息。

下面是编辑处理的代码:

AccountEditBean:

@Named(value = "accountEditBean") 
@ViewScoped 
public class AccountEditBean extends UtilityBean implements Serializable { 

    @Inject 
    ADMEndpointLocal admEndpoint; 

    private Account account; 

    public void editAccount() { 
     try { 
      admEndpoint.editAccount(this.account); 
      Messages.addInfo(ACCOUNT_DETAILS_FORM, KEY_CHANGES_SUCCESS); 
     } catch (NonUniqueException e) { 
      Messages.addError(ACCOUNT_DETAILS_FORM, e.getMessage()); 
     } catch (BaseApplicationException e) { 
      Messages.addFatal(ACCOUNT_DETAILS_FORM, e.getMessage()); 
     } 
    } 

} 

ADMEndpoint:

@Stateful 
@Transactional(Transactional.TxType.REQUIRES_NEW) 
@TransactionTracker 
public class ADMEndpoint extends LoggingStateBean implements ADMEndpointLocal, SessionSynchronization { 

    @EJB(name = "ADMAccountFacade") 
    private AccountFacadeLocal accountFacade; 

    private Account account; 

    @Override 
    public void editAccount(Account account) throws BaseApplicationException { 
     this.account.setLogin(account.getLogin()); 
     this.account.setEmail(account.getEmail()); 
     accountFacade.edit(this.account); 
    } 

} 

ADMAccountFacade:

@Stateless(name = "ADMAccountFacade") 
@Transactional(Transactional.TxType.MANDATORY) 
@TransactionTracker 
public class AccountFacade extends AbstractFacade<Account> implements AccountFacadeLocal { 

    @PersistenceContext(unitName = "myPU") 
    private EntityManager em; 

    @Override 
    public void edit(Account account) throws BaseApplicationException { 
     try { 
      em.merge(account); 
      em.flush(); 
     } catch (PersistenceException e){ 
      if(e.getMessage().contains(Account.CONSTRAINT_ACCOUNT_LOGIN_UNIQUE)){ 
       throw new NonUniqueException(NonUniqueException.MSG_NON_UNIQUE_ACCOUNT_LOGIN, e); 
      }else{ 
       throw new BaseDatabaseException(BaseDatabaseException.MSG_GENERAL_DATABASE_ERROR, e); 
      } 
     } 
    } 
} 

你知道这可能是问题的原因是什么?它出现在我的每个外观中,包含所有的自定义例外。

+0

你怎么称呼的accountFacade.edit(this.account)在ADMEndpoint类中的editAccount方法中,如果您没有帐户字段? – bitli

+0

对不起,我只是没有粘贴在这里。现在应该清楚了。 :) – Rozart

+0

然后在editAccount方法中Account参数是无用的,因为你永远不会使用它! – bitli

回答

1

我认为您应该将@Transactional更改为@TransactionAttribute,因为EJB注释了该值。 @Transactional放在managedbean在Java 7中没有在EJB中......

我在这里复制我的意见,因为我没有足够的积分去挥霍:)

+0

谢谢你解决了这个问题。但不是这样的: '@ Transactional'注释用于CDI bean,而JEE7 bean可以同时用EJB和CDI? – Rozart

+1

是的,他们可以。 managedbeans = cdi托管的bean。我只是简单地写下来。正如我上面提到的那样(正如我所知),当我们尝试在远程调用中达到它时,EJB可以是CDI bean。因此,我们使用'@ inject'而不是'@ EJB',但它不涉及事务处理。 – bitli

0

您是从它的调用将在运行时间和额外的逻辑缠着被截获的方法抛出异常:

  • 事务管理;
  • 异常处理。

你的异常不能透明地跳过这一逻辑,和规格(可能)说,一个TransactionalException将被抛出,包装你的原始异常(再次,可能 ---我不是亲密的细节) 。

+0

奇怪的是,当我实现JEE6应用程序时(当然,我使用'@ TransactionAttribute'而不是'@ Transactional')完全一样,并且我的自定义异常被正确传播。 – Rozart

+0

这种改变实际上可能是一件好事:EJB的常见缺陷之一是无法反序列化异常,导致序列化异常掩盖了原始问题。 –