【问题标题】:Spring Transaction - Do not rollback for error under specific methodSpring Transaction - 在特定方法下不回滚错误
【发布时间】:2022-01-20 08:20:21
【问题描述】:

我有一个 Spring Boot 应用程序,其中一个服务负责创建一个业务实体。为简单起见,让我们考虑:

create(Object toCreate) {
  validationService.validate(toCreate);
  Object created = repository.save(toCreate);
  notificationService.notify(created);
}

业务发生了变化,现在我希望创建如果通知失败也不会失败。

因此,我将notify() 方法包装在一个仅记录错误的try-catch 块中(即RuntimeException)。

但是,在测试时,抛出了事务回滚错误,表示连接已关闭。我不希望任何回滚,尤其是因为 NotificationService 不会修改数据库。

我如何告诉 Spring 在 NotificationService 中发生的任何异常都很好并且不需要回滚?我尝试用@Transactional(propagation=NEVER) 注释类/方法,但得到existing transaction found for transaction marked with propagation 'never'

【问题讨论】:

    标签: spring spring-boot spring-transactions


    【解决方案1】:

    也许重构代码比引入更复杂的事务处理更有帮助。

    假设您的 @Transactional 在 create() 方法上,我们可以看到您有:

    1. 预持久化业务逻辑
    2. 持久化逻辑
    3. 持久化后业务逻辑

    这取决于您的用例,但我不希望得到分数。 1 & 3 包含持久性逻辑。如果是这种情况,您可以在它自己的服务中提取持久性逻辑,该服务本身就是一个事务,而不是父级。

    如果您需要在这些步骤中进行交易,您也可以在他们自己的交易中提取它们。

    其他潜在客户可能是:

    1. default rollback behavior is for runtime unchecked exceptions。您可以使用已检查的异常来避免回滚。
    2. 如果您的通知与持久性分开并且您不关心事务,则可以将其设为异步调用(例如使用@Async)。它将在事务之外在其自身的上下文中安排。

    【讨论】:

      【解决方案2】:

      您可以使用 @Transactional 的 norollbackfor 选项,因此您必须指定一个异常类而不是服务,并且当通知中发生错误时,尝试抛出一个不会导致回滚的特定错误。

      【讨论】:

      • 您能提供更多信息吗?这个“@Transactional”应该在哪里?
      • 是的,抱歉。你应该把 @Transactional(norollbackfor = exception.class) 放在你的函数上。不是你的班级。
      • 但是使用哪种方法?创建还是通知?如果是在创建中,如果在验证和通知中都可以抛出相同的错误,但我只想忽略内部通知?
      • 关于你的创建方法。您必须在通知方法中管理可能发生的错误。使用尝试捕获。然后,您可以在通知方法中可能发生的每个错误中抛出一个特定的错误。
      猜你喜欢
      • 1970-01-01
      • 2018-09-15
      • 2016-05-03
      • 1970-01-01
      • 2017-07-22
      • 2019-07-27
      • 2019-06-29
      • 1970-01-01
      • 2017-03-27
      相关资源
      最近更新 更多