从事务回滚中排除私有方法执行



我的项目中有一个服务方法,可以这样简化:

@Transactional
public void myTransactionalMethod(){
try {
soSomethingAndSaveOnDB(); // private method
}catch (Exception exception){
saveSomethingOnDBWhenAnErrorOccurs(); // private method
throw exception;
}
}

方法是事务性的,并且正在执行一些可能导致抛出异常的主逻辑。如果发生这种情况,保存在DB中的所有数据必须恢复到以前的状态。

但是我还需要处理在catch块中抛出的异常,并在DB中写入一些额外的数据来跟踪错误。

我的实现的问题是最后的throw exception指令,它导致事务回滚,并阻止创建与错误跟踪相关的数据。

我想要禁用"事务回滚,以便在我的数据库中正确地记录错误。

注意我正在重新抛出异常以将其传播到控制器并将其转换为HTTP错误。

保留soSomethingAndSaveOnDB()saveSomethingOnDBWhenAnErrorOccurs()方法private是解决这一问题的好方法吗?

这似乎是一种变通而不是解决方案,但目前是我在评论中找到的最佳方法。

我这样修改我的方法:

@Transactional(noRollbackFor = { ExceptionWrapper.class })
public void myTransactionalMethod(){
try {
soSomethingAndSaveOnDB(); // private method
}catch (Exception exception){
saveSomethingOnDBWhenAnErrorOccurs(); // private method
throw new ExceptionWrpper(exception);
}
}

那么我定义了一个这样的类:

public class ExceptionWrapper extends RuntimeException {
private final RuntimeException wrappedThrowable;
}

最后在我的控制器中,我捕获了新的异常类型,这样:

try {
myTransactionalMethod();
}catch(ExceptionWrapper ew){
throw ew.getWrappedThrowable();
}

我想到了几个方法来解决这个问题:

  1. saveSomethingOnDBWhenAnErrorOccurs方法中使用带有PROPAGATION_REQUIRES_NEW作用域的TransactionTemplate以编程方式处理事务。这样,保存错误日志将在单独的事务中完成。例如:
private final TransactionTemplate transactionTemplate;
private void saveSomethingOnDBWhenAnErrorOccurs(){
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.execute(status-> repository.saveErrorLog());
}
  1. 使用自注入或ApplicationContext调用日志方法。然而,这种方法需要将saveSomethingOnDBWhenAnErrorOccurs方法设为public。例如,假设您的类调用MyService,那么:
@Autowired
private SomeRepository someRepository;
@Autowired
private ApplicationContext applicationContext;
@Transactional
public void myTransactionalMethod(){
try {
soSomethingAndSaveOnDB(); // private method
}catch (Exception exception){
LoggingData loggingData = ...
applicationContext.getBean(MyService.class).saveSomethingOnDBWhenAnErrorOccurs(someRepository, loggingData); // private method
throw new ExceptionWrpper(exception);
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Document saveSomethingOnDBWhenAnErrorOccurs(SomeRepository someRepository, LoggingData loggingData) {
return someRepository.save(document);
}
  1. 使用额外的抽象层,例如:
┌────────────┐
│ Controller │
└──────┬─────┘
│
│
┌─────▼─────┐
│ MyService │
└─────┬─────┘
│
│           ┌────────────────────────────────────────────────────┐
│ OnError   │@Transactional(propagation=Propagation.REQUIRES_NEW)│
└──────────►│ErrorLogging.saveSomethingOnDBWhenAnErrorOccurs     │
└────────────────────────────────────────────────────┘

相关内容

最新更新