我应该在 BLL、DAL 还是 PL 中哪里处理异常?

发布于 2024-09-05 19:06:44 字数 323 浏览 8 评论 0原文

哪个是处理异常的最佳位置? BLL、DAL 还是 PL?

我是否应该允许 DAL 和 BLL 中的方法将异常抛出链并让 PL 处理它们?或者我应该在 BLL 处理它们?

例如,

如果我的 DAL 中有一个方法发出“ExecuteNonQuery”并更新一些记录,并且由于一个或多个原因,0 行受到影响。现在,我应该如何让我的 PL 知道是否发生了异常或者确实没有与条件匹配的行。我应该在我的 PL 代码中使用“try catch”并通过异常让它知道,还是应该在 DAL 处处理异常并返回一些特殊代码,例如 (-1) 以让 PL 区分 (异常) 和 (no行匹配条件,即受影响的零行)?

Which is the best place to handle the exceptions ? BLL, DAL or PL ?

Should I allow the methods in the DAL and BLL to throw the exceptions up the chain and let the PL handle them? or should I handle them at the BLL ?

e.g

If I have a method in my DAL that issues "ExecuteNonQuery" and updates some records, and due to one or more reason, 0 rows are affected. Now, how should I let my PL know that whether an exception happened or there really was no rows matched to the condition. Should I use "try catch" in my PL code and let it know through an exception, or should I handle the exception at DAL and return some special code like (-1) to let the PL differentiate between the (exception) and (no rows matched condition i.e. zero rows affected) ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

巨坚强 2024-09-12 19:06:44

让 DAL 中引发的异常冒泡到 PL 是没有意义的 - 如果无法建立数据库连接,用户应该如何反应?

如果您能够处理异常,请尽早捕获并处理异常。不要只是吞下它们而不输出提示或日志消息 - 这将导致严重的困难和难以跟踪的错误。

It makes no sense to let an exception that is thrown in the DAL bubble up to the PL - how is the user supposed to react if the database connection could not be established?

Catch and handle exceptions early, if you can handle them. Do not just swallow them without outputting a hint or a log message - this will lead to severe difficulties and bugs that are hard to track.

静待花开 2024-09-12 19:06:44

简短的回答是这取决于!

仅当您可以利用异常做一些有用的事情时,才应该处理异常。 “有用的东西”再次取决于你在做什么。您可能想要记录异常的详细信息,尽管这并没有真正处理它,并且在大多数情况下您应该在记录后重新抛出异常。您可能希望将异常包装在其他一些(可能是自定义的)异常中,以便向异常添加更多信息。正如 @mbeckish 所说,您可能希望通过重试操作来尝试从异常中恢复 - 但是您应该小心不要永远重试。最后(请原谅双关语)您可能希望使用finally块来清理任何资源,例如打开的数据库连接。您选择对异常执行的操作将影响您处理异常的位置。对于许多异常,除了向用户报告发生了错误之外,可能没有太多有用的事情可以做,在这种情况下,在 UI 层处理异常是可以接受的并向用户报告问题(您可能还应该记录异常,进一步向下层)。

当您自己抛出异常时,您应该只在“异常”情况下抛出异常,因为抛出异常会产生很大的开销。在您的示例中,您建议如果您的操作没有更新任何记录,您可能会考虑抛出异常。这真的很特别吗?在这种情况下,更好的做法是返回更新的记录数 - 这可能仍然是需要向用户报告的错误情况,但并不像命令失败那样例外,因为与数据库的连接已下去了。

这是一篇关于异常处理最佳实践的合理文章。

The short answer is it depends!

You should only ever handle an exception if you can do something useful with it. The 'something useful' again depends on what you are doing. You may want to log the details of the exception although this isn't really handling it and you should really re-throw the exception after logging in most circumstances. You may want to wrap the exception in some other (possibly custom) exception in order to add more information to the exception. As @mbeckish touches on, you may want to try to recover from the exception by retrying the operation for example - you should be careful not to retry forever however. Finally (excuse the pun) you may want to use a finally block to clean up any resources such as an open DB connection. What you choose to do with the exception will influence where you handle it. It is likely that there isn't a great deal of useful things that can be done with many exceptions other than to report to the user that an error has occurred in which case it would be more than acceptable to handle the exception in the UI layer and report the problem to the user (you should probably log the exception as well, further down your layers).

When throwing exceptions yourself, you should only ever throw exceptions in 'exceptional'circumstances as there is a big overhead in throwing exceptions. In your example you suggest you may be thinking of throwing an exception if no records are updated by your operation. Is this really exceptional? A better thing to do in this situation would be to return the number of records updated - this may still be an error condition that needs to be reported to the user, but isn't exceptional like the command failing because the connecction to the DB has gone down.

This is a reasonable article on exception handling best practices.

冬天旳寂寞 2024-09-12 19:06:44

这是一个很大的话题,有很多不必要的争议(大声说话的人会提供不好的信息!)如果你愿意处理这个问题,请遵循 s1mm0t 的建议,这基本上是令人愉快的。

但是,如果您想要一个词的答案,请将它们放入 PL 中。认真的。如果您可以逃脱它,请将您的错误处理放入全局异常处理程序中(所有错误都应记录并提供代码以出于安全原因在生产中查找日志(特别是如果是网络),但在开发期间返回完整的详细信息速度原因)。

编辑:(澄清) 您必须处理各处的一些错误 - 但这不是“每个功能”的规范。大多数时候,让它们冒泡到 PL 并使用您自己的代码处理 .NET 的全局错误:通过通用例程从那里记录完整的调用堆栈,该例程可通过事件处理程序从所有 3 层访问(请参阅消息底部的编辑) )。这意味着您将不会将 try/catch 散布在您的所有代码中;只是您期望的部分和错误,并且可以在那里处理它,或者非关键部分,您可以在其中记录错误并通知用户不可用的功能(对于超级可靠/关键的程序来说,这种情况更加罕见)

除此之外,在处理资源有限的项目时,我经常使用“using”关键字或 try/finally/end try 而不使用 catch。用于多线程锁/互斥锁/重入预防标志/等。在所有情况下,您还需要 try/finally ,以便您的程序仍然有效(尤其是有状态应用程序)。

如果您不正确地使用异常(例如,在应该使用 IF 语句或在尝试之前检查 iffy 操作是否有效时处理非错误),这种哲学将更加崩溃。

旁注,在胖客户端应用程序中,特别是当有可能丢失大量数据或用户输入时,在尝试保存数据时进行更多尝试/捕获(当然标记为尚未有效)可能会更好)。

编辑:还需要至少在 PL 中具有日志记录例程 - 这将根据平台的不同而有所不同。我们正在开发的应用程序与 3 个 PL 版本共享 BLL/DAL:ASP.Net 版本、winforms 版本和控制台应用程序批处理模式回归测试版本。调用的日志例程实际上位于 BLL 中(DAL 仅抛出错误或完全处理它获取或重新抛出的任何错误)。然而,这会引发一个由 PL 处理的事件;在网络上,它将其放入服务器日志中,并显示网络风格的错误消息(对生产友好的消息);在 WinForms 中,会出现一个特殊的消息窗口,其中包含技术支持信息等,并在幕后记录错误(开发人员可以执行一些“秘密”操作来查看完整信息)。当然,在测试版本中,这是一个更简单的过程,但也有所不同。
除了传递参数“什么平台”之外,不知道如何在 BLL 中做到这一点,但由于它不包含日志记录所依赖的 winforms 或 asp 库,所以这仍然是一个技巧。

This is a huge topic with lots of unneeded controversy (people with loud voices giving bad info!) If you're willing to deal with that, follow s1mm0t's advice, it is mostly agreeable.

However if you want a one-word answer, put them in the PL. Serious. If you can get away with it put your error handling in a global exception handler (all errors should log and give a code to look up the log in production for security reasons (esp if web), but give the full details back during development for speed reasons).

Edit: (clarification) you have to deal with some errors everywhere - but this is not an 'every function' norm. Most of the time let them bubble up to the PL and handle .NET's global error with your own code: log the full call stack from there via a common routine that is accessible from all 3 layers via event handlers (see EDIT at bottom of message). This means you will not have try/catch sprinkled thru all your code; just sections you expect and error and can handle it right there, or, non-critical sections, with which you log the error and inform the user of unavailable functionality (this is even more rare and for super-reliable/critical programs)

Aside from that, when working with limited-resource items, I often use the 'using' keyword or try/finally/end try without the catch. for multithreading lock/mutex/re-entry prevention flags/etc. you also need try/finally in ALL cases so your program still works (especially stateful apps).

If you're using exceptions improperly (e.g., to deal with non-bugs when you should be using the IF statement or checking it an iffy operation will work before you try it), this philosophy will fall apart more.

A side note, in thick client apps especially when there is the possibility of losing significant amounts or the users' input, you may be better with more try/catches where you attempt to save the data (marked as not-yet-valid of course).

EDIT: another need for at least having the logging routine in the PL - this will work differently depending on the platform. An app we're working on shares the BLL/DAL with 3 PL versions: an ASP.Net version, a winforms version, and a console app batch mode regression testing version. The logging routine that is called is actually in the BLL (the DAL only throws errors or totally handles any it gets or re-throws them). However this raises an event that is handled by the PL; on the web it puts it in the server's log and does web-style error message display (friendly message for production); in WinForms a special message window appears with tech support info, etc. and logs the error behind the scenes (developers can do something 'secret' to see the full info). And of course in the testing version it is a much simpler process but different as well.
Not sure how I'd have done that in the BLL except for passing a parameter 'what platform,' but since it doesn't include winforms or asp libraries that the logging depends on, that still would be a trick.

喜你已久 2024-09-12 19:06:44

知道如何纠正错误的层应该是处理异常的层。
例如,如果您决定通过重试查询一定次数来处理死锁错误,那么您可以将其构建到 DAL 中。如果它继续失败,那么您可能希望让异常冒泡到下一层,然后下一层可以决定它是否知道如何正确处理此异常。

The layer that knows what to do to set things right should be the layer that handles the exception.
For example, if you decide to handle deadlock errors by retrying the query a certain number of times, then you could build that into your DAL. If it continues to fail, then you might want to let the exception bubble up to the next layer, which can then decide if it knows how to properly handle this exception.

琉璃梦幻 2024-09-12 19:06:44

应用程序中的所有层都应该妥善管理异常。这被称为横切角,因为它出现在所有层中。
我相信,使用像 Enterprise Exception Block 这样的统一框架,您最终会得到更好的整体代码。
看看这篇文章

http://msdn .microsoft.com/en-us/library/ff664698(v=PandP.50).aspx

掌握它需要一些时间,但那里有很多示例和截屏视频。

All layers in your application should manage exceptions gracefullly. This is know as a cross cutting corncern, because it appears in all your layers.
I belive that using a framework like Enterprise Exception Block with unity, you will end up with a better code overall.
Take a look at this post

http://msdn.microsoft.com/en-us/library/ff664698(v=PandP.50).aspx

It will take sometime to master it, but there are lots of examples and screencast around there.

无尽的现实 2024-09-12 19:06:44

如何处理异常取决于技术和业务需求。对于复杂或非常重要的数据库更新,我包含了将一小部分已知错误备份传递到 DL 的参数。这样,在某些情况下可以通过编程方式解决已知的错误场景。在其他情况下,需要记录错误并通知用户错误。

我习惯于通知人们错误。当然,日志记录将为我们提供详细信息,但它无法替代人类的响应时间。不仅如此,为什么还要强迫开发人员查看系统日志只是为了看看事情是否出了问题?谈论不必要的成本。

如果您有时间定义潜在的错误/异常并以编程方式解决它们,那么请务必这样做。很多时候错误/异常是意想不到的。这就是为什么为意外情况做好准备很重要,还有什么比人类参与更好的方法呢?

总的来说,在计划异常处理时应该采取防御措施。程序要么成长,要么消亡。成长的一部分就是引入错误。所以不要空转你的轮子试图杀死他们。

How to handle exceptions depends on technical and business needs. For complex or highly important database updates I include out params that pass a small list of known errors backup to the DL. This way, known error scenarios can be programmatically solved in some cases. In other cases the error needs to be logged and the user should be notified of an error.

I make a practice of notifying a human being of errors. Sure, logging will give us detailed information, but it's no replacement for the response time of a human being. Not only that, but why force developers to watch system logs just to see if things are going south? Talk about unnecessary cost.

If you have time to define potential errors/exceptions and programmatically solve them, then by all means do it. Many times errors/exceptions are unexpected. That's why it is important to be prepared for that unexpected and what better way to do that than involving a human being.

Overall, one should be on the defensive when planning exception handling. Programs grow or they die. A part of growing is introducing bugs. So don't spin your wheels trying to kill them all.

爱殇璃 2024-09-12 19:06:44

您面临的问题是异常在哪里相关?如果是数据访问异常,则应在 DAL 中捕获。如果是逻辑异常,则应在 BLL 中捕获。如果是演示异常,则在 PL 中。

例如,如果您的 DAL 抛出异常,它应该向您的 BLL 返回 null 或 false 或任何情况。如果 DAL 返回 null,您的 BLL 应该知道该怎么做,也许它会直接传递它,也许它会尝试调用另一个函数,等等。如果 BLL 从 DAL 传递 null 或返回特定内容,您的 PL 也会如此那么表示层应该能够通知最终用户存在问题。

当然,您不会收到详细的异常消息,但对于您的用户而言,这是一件好事。您应该有一个灵活的日志系统来捕获这些异常并将其报告给数据库或 ip:port 或您决定的任何内容。

本质上,如果关注点是数据问题或逻辑问题应该相应处理。

The question to you is where is the exception relevant? If it is a data access exception it should be caught in the DAL. If it is a logic exception it should be caught in the BLL. If it is a presentation exception then in the PL.

For instance if your DAL throws an exception it should return a null or a false or whatever the case may be to your BLL. Your BLL should know what to do if the DAL returns a null, maybe it passes it right through, maybe it tries calling another function, etc. The same goes with your PL if the BLL passes through a null from the DAL or returns something specific of its own then the presentation layer should be able to notify the end user that there was an issue.

Of course you won't get the verbose exception messages, but that is a good thing as far as your users are concerned. You should have a flexible logging system to catch these exceptions and report them to a database or an ip:port or whatever you decide.

Essentially you need to think in terms of separation of concerns if the concern is a data issue or a logic issue it should be handled accordingly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文