假设您有一种业务逻辑方法,可以在许多对象上执行一些操作。也许您想致电彩票号码选择Web服务,一次从列表中选择的每个人。在Java中,代码看起来像这样:

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

请注意,彩票编号Web服务可能具有副作用,例如记录该人已要求彩票号码(也许收取他们的帐户),因此,即使Web服务呼叫失败了一个人,它也可能成功了。这些信息(彩票编号)将需要回到一些更高级别(视图)。

如果这是发生单个操作的情况,则业务逻辑方法可以返回单个值(例如,彩票号)或提供任何故障细节的异常。但是对于批量操作,一些操作可能会成功,一些操作可能会失败。

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

有帮助吗?

解决方案

如果我理解,您会有某些请求可以通过的情况,有些请求可能会失败。我不确定您希望错误回来的地方,但是您可以拥有以下一个(或变体或组合)之一:

  • 错误的列表和影响的域对象。基本域对象或具有持久ID的东西可能对重复使用有用。例如,涉及域对象的错误集合。
  • 您可以将(AOP,DI)注入人对象某种错误对象/消息。例如(人。错误){...}
  • 您可以将人的收集包装到带有标题,身体,错误信息的消息中
  • 您所有的域对象都可以包括通过接口访问的错误集合;或者支持Ihaserrors界面。您可以制作此通用,并使用支持警告和验证以及各种事物的基本错误对象。

如果您处于真正的多层(而不是分层)系统中,则可能会有基于消息的体系结构,可以轻松容纳某种通用错误/警告/验证机制。 SOA/AJAX系统对此有所帮助。

如果您有一些具体的问题,请更深入地研究。

其他提示

这个问题突出了异常处理,交易和想法的适当使用之间的重要差异 工作流程“补偿” 当正确说明时,问答器正在尝试获得的东西:

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

这是一个普遍的问题,首先是您当前正在尝试的交易方法的一些背景:

数据交易最初是在双输入会计之后建模的 - 单个 信用 和相应的 借方 必须一起录制或根本没有记录。随着交易比这更大的交易,他们变得越来越有问题,无法正确实施,并且很难解决失败。当您开始跨系统边界进行一次交易的想法时,您很可能会将其误解。可以做到,但是需要复杂的且必定的更高的延期交易协调员。在一定规模上,交易是错误的心态,而薪酬开始变得更加有意义。

这是您回去看看业务实际做什么的地方。单一的大型交易很可能不是商人看到它的方式。通常,他们看到一步完成,并且根据后续结果,可能需要进行不同的措施。这是工作流和 赔偿 进来。 这是这些概念的介绍

例如,如果您从亚马逊订购了一本书,则它们可能不会在购物车中“锁定”唱片,甚至使用严格的交易来确定确认订单时是否仍然存储。他们将无论如何都会出售给您,并在可能的情况下运送它。如果他们在几周内没有设法在库存中库存,他们可能会向您发送一封电子邮件,告诉您他们正在尝试满足您的需求,您可以继续等待他们在库存中获得库存,或者您可以取消您的订单。这称为补偿,在许多现实世界中的业务流程中都是必要的。

最后,有 没有什么例外 关于任何一个。期望这可能发生并使用正常的控制流。您不应在此处使用语言的异常处理功能(何时进行例外的好规则)。您也不应依靠特定工具(WCF?)机制来查看或处理服务实施中发生的异常。通信故障应该是数据合同(故障合同)的正常部分。

不幸的是,通过“干净的处理方式”,没有一个可以神奇地照顾它的标志,您必须继续分解问题并处理所有结果。希望这些概念能将您与其他人在处理此问题时所做的一切联系在一起。

概括:

  • 您的问题已经超过了交易的概念 - >查看工作流程补偿。

祝你好运 -

我希望返回识别对象的自定义错误对象的集合,该对象由错误,错误代码和描述影响。这样,可以尝试对错误进行修复或进一步显示给用户。

我认为,如果您在这些术语中思考,您确实会过度使用例外!

返回值的值是完全可以的,而不是抛出异常。通常更好。当您无法以抽象水平恢复时,最好使用例外,但是您不应将它们作为控制流的主要手段,否则您的程序将很难阅读。

Web服务不返回异常,它将返回返回代码和消息。我将存储一些有用的表示形式,以呈现返回的信息,并返回视图或将要查看的内容的列表。

理想情况下,对您的Web服务的呼叫应该是这样。

List<Person> selectedPeople = ... //fetch list of people
callLotteryNumberWebService(selectedPeople.ToArray );

为每个人进行网络服务电话是昂贵的。在服务器端,您需要迭代列表并执行操作。服务器端代码可以抛出2个异常:BulkoperationFailDexception-如果由于db down或config文件丢失而导致致命错误。不可能进一步处理。 BulkoperationException-这包含与人有关的一系列例外。您可以坚持一些ID,以唯一地参考每个对象。您的代码将是这样:

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

当没有例外时,操作被认为是成功的。您可以使用自定义错误代码进行故障,而不是使用用户定义的异常。在服务器端构建BulkoPerationException非常棘手。其次,您需要将从服务器端列出的错误分类为BulkoperationFailDexception和BulkoperationException。这就是我在一个项目中处理的方式

我会看 DTO 对于这种任务。 DTO还可以包括有关持续存在是否成功的信息以及其他类型的“元数据”。

我可能会返回类型的结果图 Map<Person,Future<String>> 从我的 getLotteryNumbers<Collection<Person>> 服务。

然后我迭代地图,并使用 Future.get() 获取彩票号码或抛出的例外。

在我的某些服务中,我喜欢将所有调用作为单个项目调用实现,然后在我的服务中具有逻辑来将它们批量并作为一个小组处理。批处理是使用 LinkedBlockingQueue 和一个投票线程。

在这种情况下,我返回 Future<Thing> 它等待批处理结果可以使用 CountdownLatch.

在实践中查看Java并发,看看这些组件如何共同工作 http://jcip.net/

另一种方式,尤其是对于高吞吐量系统,是使用基于队列的设计,处理实体将对对象执行操作,然后基于结果将对象放在不同的队列中,以便其他实体进行其他处理,然后继续前进。这将减少由于其他处理所需的其他处理而产生的瓶颈

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top