Error handling 在多层体系结构中执行批量操作时处理错误和反馈

Error handling 在多层体系结构中执行批量操作时处理错误和反馈,error-handling,business-logic,bulk-operations,Error Handling,Business Logic,Bulk Operations,假设您有一个业务逻辑方法,可以跨多个对象执行某些操作。也许您想为从列表中选择的每个人调用一个彩票号码选择web服务。在Java中,代码可能如下所示: Set<Person> selectedPeople = ... // fetch list of people for ( Person person : selectedPeople ) { String lotteryNumber = callLotteryNumberWebService( person ); /

假设您有一个业务逻辑方法,可以跨多个对象执行某些操作。也许您想为从列表中选择的每个人调用一个彩票号码选择web服务。在Java中,代码可能如下所示:

Set<Person> selectedPeople = ... // fetch list of people
for ( Person person : selectedPeople ) {
    String lotteryNumber = callLotteryNumberWebService( person );
    // ...
}
List<Person> selectedPeople = ... // fetch list of people 

try{
    callLotteryNumberWebService(selectedPeople.ToArray);
}catch  (BulkOperationFailedException e) {
    SOP("Some config file missing/db down.No person records processed")
}catch(BulkOperationException e)  {
    UserDefinedExceptions us =  e.getExceptions()
    foreach(exception ein us)   {
        // read unique id to find which person object failed
    }
}

construct msg based on which personobject succeeded and which failed
Set selectedPeople=…//获取人员列表
for(个人:选定的个人){
字符串lotteryNumber=callLotteryNumberWebService(person);
// ...
}
请注意,彩票号码web服务可能有副作用,如记录某人已请求彩票号码(可能会向其帐户收费),因此,即使一个人的web服务调用失败,其他人的web服务调用也可能成功。这些信息(彩票号码)需要反馈到更高的层次(视图)

如果这是一个单一操作发生的情况,那么业务逻辑方法可以返回一个值(比如彩票号码),或者抛出一个异常,其中包含失败的任何细节。但对于批量操作,有几个操作可能成功,有几个操作可能失败


这似乎是在许多应用程序中都会出现的一种问题,应该有一种干净的方法来处理它。那么,将此类信息从业务逻辑层反馈到应用程序中的另一层(如视图)的最佳方式是什么呢?最好是以一种通用的方式,这种方式可以用于不同类型的数据和操作?

我更喜欢返回一组自定义的错误对象,这些对象标识了对象,这受错误、错误代码和描述的影响。通过这种方式,可以尝试纠正错误或将错误进一步显示给用户。

我可能会从我的
getLotteryNumbers
服务返回类型为
map
的结果图

然后,我将遍历映射并使用
Future.get()
获取彩票号码或抛出的异常

在我的一些服务中,我喜欢将所有调用都实现为单个项调用,然后在我的服务中使用逻辑对它们进行批处理,并将它们作为一个组进行处理。批处理是使用
LinkedBlockingQueue
和轮询线程实现的

在这个场景中,我返回一个
Future
,它使用
倒计时锁存器等待批处理结果可用


看看Java并发的实际情况,看看这些组件是如何协同工作的。DTO还可以包括关于持久化是否成功的信息以及其他类型的“元数据”。

如果你用这些术语来思考,我认为你真的过度使用了异常

返回表示失败的值而不是抛出异常是完全可以的。通常情况下更好。当您无法在抽象级别恢复时,最好使用异常,但不应将其用作控制流的主要手段,否则您的程序将很难阅读


web服务不返回异常,它返回返回代码和消息。我会存储一些有用的表示,以显示返回的信息,并返回视图或任何将要查看的信息的列表。

这个问题突出了异常处理、事务和工作流“补偿”的适当使用之间的重要区别提问者在正确陈述以下内容时,试图达到的目的是:

这似乎是在许多应用程序中都会出现的一种问题,应该有一种干净的方法来处理它

这是一个常见问题,首先是您当前尝试的事务性方法的一些背景知识:

数据交易最初是按照复式记账法建模的——一个单一的贷方和一个对应的借方必须一起记录,或者根本不记录。随着事务的规模越来越大,它们在正确实现方面的问题越来越大,处理失败也越来越困难。当您开始跨系统边界执行单个事务的想法时,您很可能是在错误地处理它。这是可以做到的,但需要复杂且必须具有更高延迟的事务协调器。在某种程度上,交易是错误的思维,补偿开始变得更有意义

这是你回头看看企业实际做什么的地方。单笔大额交易很可能不是商业人士所认为的那样。通常,他们会看到一个步骤完成,根据后续结果,可能需要采取不同的措施进行补偿。这就是工作流和薪酬的概念

例如,如果你从亚马逊订购一本书,他们可能不会在你的购物车中“锁定”该记录,甚至在确认订单时使用严格的交易来确定该书是否仍在库存中。不管怎样,他们都会把它卖给你,并在可能的时候把它运出去。如果他们在几周内还没有设法把它上市,他们可能会给你发一封电子邮件,告诉你他们正在努力满足你的需求,你可以继续等待他们把它上市,或者你可以取消订单。这称为补偿,在许多实际业务流程中都是必需的

最后,这一切都不例外。预计这种情况会发生,并使用正常的控制流。您不应该在此处()使用您的语言的异常处理功能。您也不应该依赖特定于工具(WCF?)的机制来查看或处理服务实现中发生的异常。通信故障应该是数据契约(故障契约)的正常部分

不幸的是,通过“干净的方式来处理它”,并没有可以设置的标志可以神奇地处理它,您必须继续使用d
List<Person> selectedPeople = ... // fetch list of people 

try{
    callLotteryNumberWebService(selectedPeople.ToArray);
}catch  (BulkOperationFailedException e) {
    SOP("Some config file missing/db down.No person records processed")
}catch(BulkOperationException e)  {
    UserDefinedExceptions us =  e.getExceptions()
    foreach(exception ein us)   {
        // read unique id to find which person object failed
    }
}

construct msg based on which personobject succeeded and which failed