抛出应用程序异常会导致TransactionalException

时间:2014-01-26 12:38:28

标签: java java-ee jpa exception-handling transactions

我正在实施一个JEE7 Web应用程序。在我的工作中,我发现处理自定义异常时出现问题。

我修改了帐户的属性以获得非唯一的登录字段。然后我调用了AccountEditBean#editAccount()来运行编辑过程。当进程进入AccountFacade#edit()时,我可以看到(在调试中)PersistenceException被捕获并且我的自定义NonUniqueException被抛出。问题是,异常不会传播到facade类之外,并且不会在AccountEditBean中处理。而不是在TransactionalException之后发生throw

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.

其他信息: NonUniqueException扩展BaseApplicationException,标记为@ApplicationException(rollback=true)

以下是编辑过程的代码:

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);
            }
        }
    }
}

你知道这个问题的原因是什么吗?它出现在我的每个外墙中,包含所有自定义异常。

2 个答案:

答案 0 :(得分:1)

我认为您应该将@Transactional更改为@TransactionAttribute,因为EJB会对其进行注释。 @Transactional放在java 7中的managedbean而不是EJB ...

我在这里复制了我的评论,因为我没有足够的点浪费:)

答案 1 :(得分:0)

您正在从一个方法中抛出一个异常,该方法的调用将在运行时被截获,并且其他逻辑将被包围:

  • 交易管理;
  • 异常处理。

您的异常无法透明地跳过该逻辑,并且规范(可能)表示将抛出TransactionalException,包裹您的原始异常(再次,可能 - 我不是与细节密切相关)。