我正在构建一个小型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
方法中捕获异常并抛出一个自定义异常,但没有运气。
答案 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 {
...
}