我目前正在开发一个企业解决方案,该解决方案在weblogic12c中作为EAR模块部署。我需要编写一个业务逻辑,其中将有实体管理器方法,使用 EntityManager 接口与EclipseLink对数据库执行一些更新,我需要有一个围绕这些方法的拦截器来拦截如果目标方法没有失败,则方法调用并将一些数据推送到JMS队列。
由于拦截器与拦截方法一样位于相同的事务和安全上下文中,因此如果一个失败,则会导致另一个失败,即如果通过抛出 EJBException 来完成。我的问题是关于那些在实际提交事务之前无法捕获的事务回滚异常。因此,即使截获的方法获得 RollbackException ,拦截器也不会立即终止,因为它在同一个事务模型中运行,因此它无法捕获这些回滚异常。最终它也被回滚,但与此同时,数据被推送到JMS队列,这是不太理想的。
我也不能将JMS队列部分从拦截器中取出,因为作为软件需求,如果模块无法将数据推送到jms,则事务也应该失败并回滚。所以我想在这里实现的是,如果截获的方法失败,事务也会失败,除了context.proceed()方法调用之外,拦截器中不应该执行任何执行。
现在,假设我有一个商业方法:
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Interceptors(TestInterceptor.class)
@Override
public TestBean update(TestBean testBean) {
try {
TestEntity testEntity = em.createNamedQuery("TestEntity.findById", TestEntity.class)
.setParameter("id", testBean.getId())
.getSingleResult();
// only some bean conversions before merging
testEntity.setName(testBean.getName());
testEntity.setPhone(testBean.getPhone());
testEntity.setImage(testBean.getImage());
em.merge(testEntity);
em.flush();
testBean.setVersion(testEntity.getVersion());
logger.debug("Update successful");
return testBean;
} catch (Exception ex) {
logger.debug("update::exception: ", ex);
throw ex;
}
}
一种网络服务方法:
@MethodPrivilege(MethodRole.GENERIC)
@WebMethod
@Override
public String testDataCRUD(@WebParam(name = "auth") AuthRequest authRequest,
@WebParam(name = "id") Long id,
@WebParam(name = "name") String name,
@WebParam(name = "phone") String phone,
@WebParam(name = "image") byte[] image,
@WebParam(name = "action") Action action) {
...
// build testBean from received parameters
...
try {
testManager.update(testBean);
return "SUCCESS";
} catch(Exception ex) {
return "FAILED -- UPDATE Error: " + ex.getMessage();
}
}
最后这里是拦截器方法:
@AroundInvoke
private Object around(InvocationContext ctx) throws Exception {
Object testParam = null;
TestBean testBean = null;
logger.debug("Test intercepted");
try {
testParam = ctx.proceed();
} catch(Exception ex) {
logger.debug("Interceptor exception ", ex);
throw new EJBException("Target method raised an exception");
}
// do some bean conversion here
...
...
// construct the message object here
boolean success = jmsNotifier.send(message, false);
if(!success) {
throw new Exception("JMS failed.");
}
logger.debug("Successfully sent to jms");
return testParam;
}
现在,如果业务方法获得RollbackException,则服务层可以捕获它,因为业务方法启动了新事务。但到目前为止,我无法在ctx.proceed()周围的try catch块中捕获它;结果,代码继续并将数据推送到jms队列,然后在事务完成时获取异常。我该如何解决这个问题? 注意:对不起我的英语不好,如果我需要澄清其中的某些部分,请告诉我。
更新 :(在Display Name is missing发表评论后)
为了描述我这样做的原因 - 例如,我在现有的ejb项目中添加了一个额外的jar包,服务层和业务/实体管理器层来自现有的应用程序。现在,我添加的额外ejb jar围绕目标业务方法执行一些额外的东西,并且可以有很多这样的方法。因此,我的任何同事都可以抓住jar,将其添加到他们的项目中,我需要一种方法,这样就需要他们对业务或实体方法进行少量更改。到目前为止我所尝试的是,他们需要做的就是添加一个Interceptor类,然后可以使用我的插件库的功能。这样,只有业务层所需的更改是添加一条额外的行,说明@Interceptor注释和现有的代码库在很大程度上没有被修改。
还尝试添加em.flush(),但在描述的情况下没有帮助。非常感谢任何帮助。
答案 0 :(得分:-1)
两件事 -
1)RollbackException是一个运行时异常,因此catch(Exception e)将不起作用。你需要像catch(Throwable t)这样的东西拦截一切。
2)你可以将你的JMS逻辑放在try块中,这样如果ctx.proceed()抛出,你就永远不会遇到JMS代码。
希望这有帮助。