java - 在多个资源请求的情况下还原更改的最佳实践是什么?
问题描述
我有一种方法可以对与文件系统和数据库交互的某些服务进行多次调用。问题是我实际上不知道如何正确实施错误处理,以防中途出现问题。好吧,就我而言,Spring 会使用@Transactional
注释恢复所有数据库更改。但是文件系统呢?目前我想到的一切都是这样的:
public void myMethod() throws MyMethodException{
try {
doFirstThingWithDatabase();
doSecondThingWithDatabase();
doFirstThingWithFileSystem();
doSecondThingWithFileSystem();
} catch(FirstDatabaseThingException e) {
logger.error(e.getMessage());
throw new MyMethodException(e);
} catch(SecondThingWithDatabaseException(e) {
logger.error(e.getMessage());
revertFirstDatabaseChange();
throw new MyMethodException(e);
} catch(FirstFSThingException e) {
logger.error(e.getMessage());
revertFirstDatabaseChange();
revertSecondDatabaseChange(); //and what if first reversion is impossible and also throws an exception?
throw new MyMethodException(e);
} catch(SecondFSThingException e) {
logger.error(e.getMessage);
revertFirstDatabaseChange();
revertSecondDatabaseChange();
revertFirstFSChange();
throw new MyMethodException(e);
}
}
但这对我来说似乎很难看,因为我重复了一些代码。这种情况的最佳做法是什么?
解决方案
您可以使用 Spring 事件和事件侦听器。
在 DB 服务中,在执行可能引发 DB 异常的语句之前,发布一个事件,TransactionalEventListener
如果出现事务回滚,则允许执行特定的回滚处理。
这可能看起来像:
@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);
}
}
推荐阅读
- heroku - 在heroku中部署mern应用程序,出现以下错误
- python - 使用 pd.read_sql 和 asyncio 从数据库读取
- r - 如果选择取决于另一个输入,则 shinyStore 无法恢复 selectizeInput 的选定值
- apache-spark - Spark-Cassandra , 如何基于 Query 获取数据
- html - 如何使用引导程序将按钮放置在 Textarea 旁边而没有任何空格
- javascript - 检查文本是否包含确切单词的脚本
- javascript - 使用带有条件的聚合连接多个集合
- php - 使用 symfony 进行登录的反应路由
- firebase - 如何安排云功能来更新 Firebase 实时数据库中的每个用户?
- javascript - Moment Timezone 没有 IST 的数据