Java 事务失败时将异常堆栈跟踪提交到数据库

Java 事务失败时将异常堆栈跟踪提交到数据库,java,spring,transactions,spring-transactions,Java,Spring,Transactions,Spring Transactions,我有我的事务公共方法,它试图从数据库中删除许多内容。 还有一个数据库表,包含删除过程中的错误信息。 然而,我需要它以这样的方式工作:当删除过程中抛出异常时,所有删除都将回滚,并使用异常堆栈跟踪将新条目提交到数据库。 我的代码如下所示: class Clazz{ @Transactional public void classMethod(){ try { deleteStuff(); } cat

我有我的事务公共方法,它试图从数据库中删除许多内容。 还有一个数据库表,包含删除过程中的错误信息。 然而,我需要它以这样的方式工作:当删除过程中抛出异常时,所有删除都将回滚,并使用异常堆栈跟踪将新条目提交到数据库。 我的代码如下所示:

class Clazz{
     
     @Transactional
     public void classMethod(){
          try {
               deleteStuff();
          } catch (Exception e) {
               logRepository.save(new ErrorLog(e.getMessage()));
          }
     }
}
就我而言,这段代码不起作用,因为在try-catch块中捕获了异常,所以日志将保存到数据库中,但删除不会回滚。 我已经阅读了
TransactionSynchronizationAdapter#afterCompletion
方法,但无法访问该方法引发的异常的堆栈跟踪

所以我的问题是,有没有办法捕获异常、将堆栈跟踪保存到数据库并回滚所有其他提交? 提前谢谢。

是的,有。
您可以编写自己的拦截器。
为此,您需要有自己的注释:

@InterceptorBinding
@Inherited
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@Documented
public @interface LogExceptions {

}
然后,您必须对您的方法进行注释:

class Clazz{
     
     @Transactional(value = TxType.REQUIRES_NEW)
     @LogExceptions
     public void classMethod(){
         deleteStuff();
     }
}
并编写一个拦截器:

@Interceptor
@LogExceptions
@Priority(Interceptor.Priority.PLATFORM_BEFORE + 100) //intercept before the TransactionalInterceptor at 200
public class LogExceptionsInterceptor {

    public LogExceptionsInterceptor() {}
    
    @Inject
    LogBean logBean;  //some bean to persist the exception

    @AroundInvoke
    public Object aroundInvoke(InvocationContext ic) throws Exception {
        Object result = null;

        LogEntry logEntry = new LogEntry(); //a entity for the stacktrace
        
        try {
            result = ic.proceed();
        }catch (Exception e) {
            
            StringWriter s = new StringWriter();
            e.printStackTrace(new PrintWriter(s));
            logEntry.setStacktrace(s.toString());
            logBean.persist(logEntry);
        }

        return result;
    }

}
最后,您必须激活beans.xml中的拦截器:

<?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_2_0.xsd"
    bean-discovery-mode="all" version="2.0">
    <interceptors>
        <class>your.package.LogExceptionsInterceptor</class>
    </interceptors>
</beans>

your.package.LogExceptionsInterceptor
这里有一个好教程的链接: