【问题标题】:Transaction rollback and save info交易回滚并保存信息
【发布时间】:2016-08-10 23:35:55
【问题描述】:

在服务层,我有一些带有事务注释的方法。

@Transactional
public void process() throws ProcessPaymentException{ 
    try{
    .... do some operation
    catch (ProcessPaymentException ppe) {
        save db problem issue.
    }
}

似乎如果有问题,有回滚......并且没有任何东西保存在数据库中......

ProcessPaymentException 扩展异常

有没有办法在 try 中回滚进程但在 catch 中保存?

编辑

如果此链接正常,嵌套事务可能是一种解决方案 https://www.credera.com/blog/technology-insights/java/common-oversights-utilizing-nested-transactions-spring/

【问题讨论】:

  • 你应该覆盖默认的回滚实现。 @Transactional 有一个名为 rollbackfor 的属性,您可以尝试在那里实现一个新属性。另一个选项应该是方面,实现异常方面。

标签: spring spring-data-jpa mariadb spring-transactions


【解决方案1】:

使用ControllerAdvise 的现有答案应该有助于正常设置传入请求来自 Spring MVC(即通过 Controller)。

对于不是这样的情况,或者您不想将异常处理逻辑绑定到 Spring MVC,这里有一些我能想到的替代方案

(这里我假设您希望依赖声明式事务控制,而不是自己以编程方式控制事务)

  1. 单独的服务/组件以在不同的事务中保存错误。

    简而言之,您可以拥有一个单独的服务,它通过传播REQUIRES_NEW 创建自己的事务。例如

    @Service
    public class FooService
        @Inject
        private ErrorAuditService errorAuditService;
    
        @Transactional
        public void process() throws ProcessPaymentException{ 
            try{
            .... do some operation
            catch (ProcessPaymentException ppe) {
                errorAuditService.saveErrorAudit(ppe.getErrorText());
                throw ppe;  // I guess you want to re-throw the exception
            }
        }
    }
    
    
    @Service
    public class ErrorAuditService
        @Transactional(propagation=REQUIRES_NEW)
        public void saveErrorAudit() { 
            // save to DB
        }
    }
    
  2. 更进一步,如果对不同服务的错误处理相同,您可以创建一个通知,当服务方法抛出异常时将调用该通知。在该建议中,您可以将错误保存在 db 中(使用 ErrorAuditService),然后重新抛出异常。

【讨论】:

  • 另一种选择是使用自引用,即使用相同的服务。在这种情况下,您只需将FooService 注入自身(通过@Autowired @Lazy private FooService selfReference;),然后您可以将REQUIRES_NEW 应用于本地方法,最后通过注入的自引用调用此方法:selfReference.saveErrorAudit() - 每当您需要它时嵌套事务。
【解决方案2】:

因为 try-catch 的过程被同一个事务包装。 每当抛出异常时,事务管理器都会回滚。所以,没有东西会被保存。

有没有办法在 try 中回滚进程但在 catch 中保存?

是的。创建异常处理程序以在回滚后保存数据库问题。 就是这个想法

@ControllerAdvice
public class HandlerName {
    @ExceptionHandler(ProcessPaymentException.class)
    public void saveDbIssue(ProcessPaymentException ex) {
        // save db problem issue.
}

但它只有在你想保存静态数据时才有效。

【讨论】:

  • 无法将字符串传递给此方法或字符串列表?
  • 您可以将一个字符串传递给 ProcessPaymentException 的构造函数,然后将其作为 saveDbIssue 方法参数。
  • 我相信ControllerAdvice 仅适用于Controllers 的异常处理程序。即,如果对 OP 服务的传入请求不是通过 Controller 发出的,则此方法将不起作用。
猜你喜欢
  • 2014-08-05
  • 1970-01-01
  • 2021-09-19
  • 1970-01-01
  • 1970-01-01
  • 2020-09-19
  • 2014-10-29
  • 2020-07-10
  • 1970-01-01
相关资源
最近更新 更多