2

我正在构建一个小型 JavaEE 项目并有一个存储库类:

@Stateless
public class UserRepository extends AbstractRepository<User> {

    @PersistenceContext
    private EntityManager em;

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

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

我有使用此功能的服务类:

@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。我读了为什么我不能捕获 EJB 异常?但这个问题本身并没有真正的答案。

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

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

4

4 回答 4

1

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

摘自 EJB 3.1 规范第 386 页

方法条件:Bean方法在调用者事务的上下文中运行[注A]。这种情况可能发生在Required、Mandatory 和Supports 属性中。

你的条件满足这个

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

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

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

容器的操作
记录异常或错误 [注 B]。
将事务标记为回滚。
丢弃实例 [注 C]。
向客户端抛出 javax.ejb.EJBTransactionRolledbackException。[著名的]

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

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

此外,以防万一您想捕获异常,请在 em.createQuery(query).getSingleResult(); 周围添加 try-catch 子句 在 UserRepository 类中。这也将删除您获得的异常跟踪日志。

于 2013-07-18T13:59:24.543 回答
0

在 Sameer Mali 的帮助下,我发现了事务被回滚的原因。然后可以通过抛出具有@ApplicationException注释的异常来避免跟踪日志。此外,异常可能不会继承自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 {
    ...
}
于 2013-08-12T13:51:40.307 回答
0

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

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

于 2013-07-18T13:10:04.953 回答
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 创建另一个事务。最好您非常谨慎地决定您将在哪里开始、加入或开始/新事务(例如,您也可以强制拥有当前事务或使其不绑定到任何事务(这有助于提高性能)) .

问候, 栾

于 2013-07-18T13:31:37.723 回答