JavaEE EJB无法捕获TransactionRolledbackException

时间:2013-07-18 12:45:50

标签: java-ee exception jpa ejb

我正在构建一个小型JavaEE项目并拥有一个Repository Class:

@Stateless
public class UserRepository extends AbstractRepository<User> {

    @PersistenceContext
    private EntityManager em;

    public User getByName(String username) {
       CriteriaBuilder criteriaBuilder = ...

       return em.createQuery(query).getSingleResult();
    }
}

我有使用此功能的Service类:

@Stateless
public class UserService extends AbstractService<User> {
    public User getByName(String username) {
        try {
            return userRepository.getByName(username);
        } catch (Throwable e) {
            // says: "Caught: EJBTransactionRolledbackException"
            System.out.println("Caught: " + e.getClass());
            return null;
        }
    }
}

我希望catch (Throwable e)子句可以捕获此方法中可能发生的任何事情,但显然我错了。我的日志中仍然有一个TransactionRolledbackException。我读过Why can't I catch EJB exceptions?,但问题本身并没有真正的答案。

为什么TransactionRolledbackException仍然被抛出?我如何防止这种情况?此外,它与实际被捕获的EJBTransactionRolledbackException有什么关系?

我也尝试在getByName方法中捕获异常并抛出一个自定义异常,但没有运气。

4 个答案:

答案 0 :(得分:1)

根据您的源代码
UserService = EJB客户端
UserRepository =由客户端调用的EJB /被调用的EJB
由于没有指定Transaction属性,因此默认为REQUEIRED,因此事务上下文正在从UserService传播到UserRepository,即所有内容都在单个事务中执行。

使用EJB 3.1规范第386页的一些摘录

  

方法条件:Bean方法在调用者的上下文中运行   交易[注A]。这种情况可能发生在必需,强制性,   和支持属性。

你的病情满足了这个

  

方法异常:所有其他异常和错误

这基本上意味着系统异常被抛出,这是你的情况(应用程序异常是EJB中的另一个,太多无法解释)

最重要的部分是跟随容器行动

  

集装箱的行动
  记录异常或错误[注B]   标记事务以进行回滚。
  丢弃实例[注释C]。
  将javax.ejb.EJBTransactionRolledbackException抛出到客户端。 [注D]

因此,根据您的源代码UserService,客户端将收到EJBTransactionRolledbackException 请阅读规范以便更好地理解。

我希望这能回答你的问题。

另外,如果你想捕获异常,请添加try-catch子句         em.createQuery(查询).getSingleResult(); 在UserRepository类中。这也将删除你得到的异常tracelog。

答案 1 :(得分:0)

当您从另一个EJB方法调用一个EJB方法时,默认情况下它将加入同一个事务。因此,回滚仅发生在最外层的方法中。您可以将外部方法更改为使用BMT而不是CMT,然后您将控制事务提交并处理错误。

如果您希望内部调用独立,您还可以使内部调用使用新事务。

答案 2 :(得分:0)

这是因为EJB的默认行为是使用(http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttributeType.html#REQUIRED),它会将所有调用连接到单个事务中。好吧,您可以使用带有http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttributeType.html#REQUIRES_NEW的TransactionAttribute强制创建另一个事务。您可以非常谨慎地决定启动,加入或启动/新事务(您还可以强制拥有当前事务或使其不受任何事务约束(这有助于提高性能),例如)

此致 栾

答案 3 :(得分:0)

在Sameer Mali的帮助下,我找到了为什么交易被回滚。然后可以通过抛出具有@ApplicationException注释的异常来避免tracelog。此外,异常可能不会从Throwable继承,但必须从Exception继承(这无论如何都是合理的)。代码最终如下:

public User getByName(String username) {
   CriteriaBuilder criteriaBuilder = ...

   try {
       return em.createQuery(query).getSingleResult();
   } catch (NoSuchResultException e){ // Note: this is a System Exception
       throw new NoSuchUserException(username);
   }
}

@ApplicationException
public class NoSuchUserException {
    ...
}