当前位置: 首页 > 面试题库 >

您如何找出导致CDI事务回滚的异常?

阎善
2023-03-14
问题内容

我们正在将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重新抛出嵌套错误的方法,以便您可以轻松调试回滚的真正原因是什么?

(在Java-EE7,Glassfish 4.0,JSF 2.2.2上运行)


问题答案:

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

@InterceptorBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionDebugger {
}

定义CDI拦截器后,我们需要创建在使用拦截器注释时执行的类。我们定义一个@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;
    }
}

接下来,由于在CDI中默认未启用拦截器,因此必须在bean.xml(通常位于src / META-
INF)中包括新的拦截器。这必须在使用注释的所有项目中完成,而不仅仅是在定义注释的项目中。这是因为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拦截器调用的方法。在这里,我们用@Transactional注释它们以启动事务,并用@TransactionDebugger注释以捕获在事务中发生的任何异常:

@Transactional @TransactionDebugger
public void init() {
    ...
}

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



 类似资料:
  • 我们使用CDI和CMT(容器管理事务)连接到web应用程序中的数据库,并标记从前端调用的方法,这些方法需要使用以下事务: 这将创建一个新的CDI事务,但是现在如果在执行此代码块或从此方法调用的任何其他代码块时发生异常,它将抛出错误消息: 有没有办法让CDI重新抛出嵌套错误,以便您可以轻松地调试回滚的真正原因是什么? (在 Java-EE7、Glassfish 4.0、JSF 2.2.2 上运行)

  • 我正在与用propagation.requires_new注释的方法的奇怪行为作斗争。 以下是TransactionManager的日志:

  • Spring 4.1.4 Hibernate 4.2.0 JDK 1.8 我的上下文:我有一个控制器调用-->Service-->调用Dao业务功能是删除(在1到许多DB关系中)一些子级,但不是所有子级。然后,在删除了一些子项之后,我尝试删除父项,然后我得到了java.sql.SqlIntegrityConstraintViolationException

  • 情景故事时间: 我“继承”了一个程序,一个用于访问数据库的相当简单的webservice。该程序在某个地方有一个缺陷:它试图更新一个没有更新授权的表。该程序只具有更新数据库队列的权限(Oracle),以保存谁访问了什么信息。这是不受欢迎的行为,现在我纠正了它。注意:这与这个问题本身无关,它只是导致我提出这个问题的原因。 该程序使用Spring+Hibernate来管理和访问数据和事务。 因为程序的

  • 我在tomcat服务器中使用具有多个数据源配置的JTA原子事务。有时我会遇到以下异常: JTA事务意外回滚(可能是由于超时);嵌套的异常是javax。交易回滚异常:事务被设置为仅回滚 出现这种异常的原因是什么?

  • 这很好,但并不总是在代码中抛出运行时异常。因此,我挖掘并发现如下所示的rollbackFor; 现在,我必须更改所有代码,以使用RollBackfor更改@Transactional。但是还有其他方法可以将所有@transaction advice属性更改为rollbackFor=exception.class吗?