我们使用CDI和CMT (容器管理事务)连接到web应用程序中的数据库,并标记从前端调用的方法,这些方法需要:
@Transactional(value=TxType.REQUIRES_NEW)这将创建一个新的CDI事务,但是,如果发生异常,执行此代码块或从此方法调用的任何其他代码块,则将引发错误消息:
javax.transaction.TransactionalException: Managed bean with Transactional annotation and TxType of REQUIRES_NEW encountered exception during commit javax.transaction.RollbackException: Transaction marked for rollback.
...
Caused by: javax.transaction.TransactionalException: Managed bean with Transactional annotation and TxType of REQUIRES_NEW encountered exception during commit javax.transaction.RollbackException: Transaction marked for rollback.
...
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.不管怎样,是否需要CDI重新抛出嵌套错误,以便您可以轻松地调试回滚的真正原因?
(运行在JavaEE7、Glassfish 4.0、JSF2.2.2上)
发布于 2013-11-22 08:17:23
似乎最简单的方法是使用CDI拦截器来捕获异常。我们可以将CDI阻断器定义为:
@InterceptorBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionDebugger {
}一旦定义了CDI拦截器,就需要创建在使用Interceptor注释时执行的类。我们定义一个@AroundInvoke,以便在我们注释的方法中的代码之前调用我们的代码。invocationContext.proceed()将调用我们注释的方法,并给我们返回的结果(如果有的话)。因此,我们可以在这个调用周围放置一个try, catch (Exception)来捕获抛出的任何类型的异常。然后,我们可以使用记录器(此处使用的log4j)记录此异常,并重新抛出异常,以便任何上游代码也被告知该异常。
重新抛出异常也将允许我们使用CMT (容器管理事务),因为最终容器将捕获异常并抛出事务RollbackException。但是,您也可以很容易地使用UserTransactions,并在捕获异常时执行手动回滚,而不是重新抛出异常。
@Interceptor
@TransactionDebugger
public class TransactionInterceptor {
private Logger logger = LogManager.getLogger();
@AroundInvoke
public Object runInTransaction(InvocationContext invocationContext) throws Exception {
Object result = null;
try {
result = invocationContext.proceed();
} catch (Exception e) {
logger.error("Error encountered during Transaction.", e);
throw e;
}
return result;
}
}接下来,我们必须在beans.xml中包含新的拦截器(通常位于src/META中),因为在CDI中默认情况下不启用拦截器。这必须在使用注释的所有项目中完成,而不仅仅是定义注释的项目。这是因为CDI根据每个项目初始化拦截器:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
<interceptors>
<class>package.database.TransactionInterceptor</class>
</interceptors>
</beans>最后,我们必须用新的CDI拦截器对我们调用的方法进行注释。在这里,我们对它们进行了注释,使用@ transaction启动事务,并使用@TransactionDebugger来捕获事务中发生的任何异常:
@Transactional @TransactionDebugger
public void init() {
...
}这将记录在执行init()代码时发生的任何错误。可以通过在Interceptor实现类TransactionInterceptor中将try、catch从异常更改为异常的子类来更改日志粒度。
https://stackoverflow.com/questions/18888572
复制相似问题