Spring Transaction - 在特定方法下不回滚错误

Posted

技术标签:

【中文标题】Spring Transaction - 在特定方法下不回滚错误【英文标题】:Spring Transaction - Do not rollback for error under specific method 【发布时间】: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'

【问题讨论】:

【参考方案1】:

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

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

    预持久化业务逻辑 持久化逻辑 持久化后业务逻辑

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

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

其他潜在客户可能是:

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

【讨论】:

【参考方案2】:

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

【讨论】:

您能提供更多信息吗?这个“@Transactional”应该在哪里? 是的,抱歉。你应该把 @Transactional(norollbackfor = exception.class) 放在你的函数上。不是你的班级。 但是使用哪种方法?创建还是通知?如果是在创建中,如果在验证和通知中都可以抛出相同的错误,但我只想忽略内部通知? 关于你的创建方法。您必须在通知方法中管理可能发生的错误。使用尝试捕获。然后,您可以在通知方法中可能发生的每个错误中抛出一个特定的错误。

以上是关于Spring Transaction - 在特定方法下不回滚错误的主要内容,如果未能解决你的问题,请参考以下文章

JDBC中Transaction的实现

spring transaction注解原理

java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()L

Spring中层之间的@Transaction注解

Spring Transaction:如果我不在方法上给出@Transaction 注释会发生啥

Spring Boot Stomp-Transaction Sockjs: ERROR message=[Bad transaction] Invalid transaction identifier