Java 在多个资源请求的情况下恢复更改的最佳做法是什么?

Java 在多个资源请求的情况下恢复更改的最佳做法是什么?,java,spring,exception,Java,Spring,Exception,我有一个方法可以对一些与文件系统和数据库交互的服务进行多次调用。问题是我实际上不知道如何正确地实现错误处理,以防中途出错。就我而言,Spring将使用@Transactional注释恢复所有数据库更改。但是文件系统呢? 我现在想到的一切都是这样的: public void myMethod()引发MyMethodException{ 试一试{ doFirstThingWithDatabase(); doSecondThingWithDatabase(); doFirstThingWithFile

我有一个方法可以对一些与文件系统和数据库交互的服务进行多次调用。问题是我实际上不知道如何正确地实现错误处理,以防中途出错。就我而言,Spring将使用
@Transactional
注释恢复所有数据库更改。但是文件系统呢? 我现在想到的一切都是这样的:

public void myMethod()引发MyMethodException{
试一试{
doFirstThingWithDatabase();
doSecondThingWithDatabase();
doFirstThingWithFileSystem();
doSecondThingWithFileSystem();
}捕获(FirstDatabaseThingException e){
logger.error(例如getMessage());
抛出新的MyMethodException(e);
}catch(SecondThingWithDatabaseException(e){
logger.error(例如getMessage());
revertFirstDatabaseChange();
抛出新的MyMethodException(e);
}捕获(FirstFSThingException e){
logger.error(例如getMessage());
revertFirstDatabaseChange();
revertSecondDatabaseChange();//如果第一次恢复不可能,并且还会引发异常,该怎么办?
抛出新的MyMethodException(e);
}捕获(第二个FsThingException e){
记录器错误(例如getMessage);
revertFirstDatabaseChange();
revertSecondDatabaseChange();
revertFirstFSChange();
抛出新的MyMethodException(e);
}
}

但是,由于我重复了一些代码,这对我来说似乎很难看。对于这种情况,最佳做法是什么?

您可以使用Spring事件和事件侦听器

在DB服务中,在执行可能引发DB异常的语句之前, 发布一个事件,该事件将允许在出现事务回滚时执行特定的回滚处理。
这可能看起来像:

@Transactional
public void doFirstThingWithDatabase(Foo foo) {
    applicationEventPublisher.publishEvent(new FooInsertionEvent(foo));
    fooRepo.save(foo);
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void rollBackFooInsertion(FooInsertionEvent fooInsertionEvent) { 
    String info = fooInsertionEvent.getAnyRequiredInfo();
    // use that info to make the DB in the correct state
}
public void myMethod() throws MyMethodException{
    try {
        doFirstThingWithDatabase(); // processed by the listener
        doSecondThingWithDatabase();  // processed by the listener
        doFirstThingWithFileSystem();  // processed below when doSecondThingWithFileSystem() fails
        doSecondThingWithFileSystem(); // no required
    } catch(SecondFSThingException e) {
        logger.error(e.getMessage);
        revertFirstFSChange();
        throw new MyMethodException(e);
    }
    catch(Exception e) {
        logger.error(e.getMessage);
        throw new MyMethodException(e);
    }

}
这样,与该DB异常相关的自定义逻辑回滚将在没有任何捕获的情况下执行

最后,您的代码可能如下所示:

@Transactional
public void doFirstThingWithDatabase(Foo foo) {
    applicationEventPublisher.publishEvent(new FooInsertionEvent(foo));
    fooRepo.save(foo);
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void rollBackFooInsertion(FooInsertionEvent fooInsertionEvent) { 
    String info = fooInsertionEvent.getAnyRequiredInfo();
    // use that info to make the DB in the correct state
}
public void myMethod() throws MyMethodException{
    try {
        doFirstThingWithDatabase(); // processed by the listener
        doSecondThingWithDatabase();  // processed by the listener
        doFirstThingWithFileSystem();  // processed below when doSecondThingWithFileSystem() fails
        doSecondThingWithFileSystem(); // no required
    } catch(SecondFSThingException e) {
        logger.error(e.getMessage);
        revertFirstFSChange();
        throw new MyMethodException(e);
    }
    catch(Exception e) {
        logger.error(e.getMessage);
        throw new MyMethodException(e);
    }

}

您不能对所有异常使用一个catch块,然后在任何异常出现时尝试还原每个catch块吗?