首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何找到导致CDI事务回滚的异常?

如何找到导致CDI事务回滚的异常?
EN

Stack Overflow用户
提问于 2013-09-19 07:25:10
回答 2查看 4.9K关注 0票数 6

我们使用CDI和CMT (容器管理事务)连接到web应用程序中的数据库,并标记从前端调用的方法,这些方法需要:

代码语言:javascript
运行
复制
@Transactional(value=TxType.REQUIRES_NEW)

这将创建一个新的CDI事务,但是,如果发生异常,执行此代码块或从此方法调用的任何其他代码块,则将引发错误消息:

代码语言:javascript
运行
复制
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上)

EN

Stack Overflow用户

回答已采纳

发布于 2013-11-22 08:17:23

似乎最简单的方法是使用CDI拦截器来捕获异常。我们可以将CDI阻断器定义为:

代码语言:javascript
运行
复制
@InterceptorBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionDebugger {
}

一旦定义了CDI拦截器,就需要创建在使用Interceptor注释时执行的类。我们定义一个@AroundInvoke,以便在我们注释的方法中的代码之前调用我们的代码。invocationContext.proceed()将调用我们注释的方法,并给我们返回的结果(如果有的话)。因此,我们可以在这个调用周围放置一个try, catch (Exception)来捕获抛出的任何类型的异常。然后,我们可以使用记录器(此处使用的log4j)记录此异常,并重新抛出异常,以便任何上游代码也被告知该异常。

重新抛出异常也将允许我们使用CMT (容器管理事务),因为最终容器将捕获异常并抛出事务RollbackException。但是,您也可以很容易地使用UserTransactions,并在捕获异常时执行手动回滚,而不是重新抛出异常。

代码语言:javascript
运行
复制
@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根据每个项目初始化拦截器:

代码语言:javascript
运行
复制
<?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来捕获事务中发生的任何异常:

代码语言:javascript
运行
复制
@Transactional @TransactionDebugger
public void init() {
    ...
}

这将记录在执行init()代码时发生的任何错误。可以通过在Interceptor实现类TransactionInterceptor中将try、catch从异常更改为异常的子类来更改日志粒度。

票数 8
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18888572

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档