在处理 n 层时捕获调用堆栈高位的异常?
假设我有 3 层应用程序 - 前端域和数据访问。我读过,在调用堆栈中捕获高位异常是一个好主意...因此,如果我收到数据访问异常,域层只会执行finally,就像这样
try{
}finally{ //清理 并
让数据访问异常渗透到前端层。让前端层处理内部结构,这不会破坏分层吗?我认为每一层都应该处理程序或包装并抛出它无法处理其调用层的异常...... 有什么想法吗?
Say I have 3 tier app- frontend domain and data access. I have read that it is a good idea to catch exceptions high in the call stack...so if I get a data-access exception, the domain layer merely does a finally, like so
try{
}finally{
//cleans up
}
and lets the data-access exception percolate to the frontend layer. Does this not break layering by making the front-end layer deal with the innards ? I think that each layer should either handler or wrap and throw exception that it cannot handle to its calling layer...
any thoughts ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
目前为止收到了很多很好的反馈,我会告诉你我的看法。
规则#1。仅捕获您要实际处理的异常。我所说的处理是指以这样的方式进行处理,以便客户端的请求可以继续。您可能会捕获足够长的时间来记录信息(不要滥用这一点,通常堆栈有足够的信息)或转换为更容易传播的不同错误(基于运行时)。但是,如果你无法处理它,就不要费心去抓住它。这只是额外的代码,无用且令人困惑。即使您记录或转换,您最终也会重新抛出。
意识到大多数时候,您无法处理异常。确实。许多人未能领会这一点。但现实是,如果您在读取或写入磁盘时遇到 IOException,游戏就结束了。无法为用户完成该请求。如果您的网络不稳定并且无法与数据库通信,同样的情况。
规则#2。当您确实遇到无法处理的异常时,您唯一能做的就是尝试以对用户有帮助的方式失败。这意味着,将其记录下来以供以后分析(包括原始堆栈/原因),然后向用户报告尽可能有帮助的内容。清理所有必须清理的内容,使系统保持一致的状态。
鉴于与最终用户的这种沟通发生在非常高的级别,这意味着您通常必须抓住该级别。大多数时候,我发现在起始点和捕获异常以记录并向用户报告的顶层之间的任何异常处理都没有什么价值。我经常转换为 RuntimeException 的一种形式,但这只是为了简化各层的传播。
最重要也是最重要的事情是要认识到您通常无法处理异常,因此为异常编写的任何代码都应该尽可能简单。
Lots of good feedback so far, I'll give you my take.
Rule #1. ONLY catch exceptions you are going to actually handle. By handle, I mean handle in such a way that the client's request can continue. You may catch things long enough to log information (don't abuse this, usually the stack is enough information) or to convert to a different error that propagates easier (ala Runtime based). But, if you can't handle it, don't bother catching it. That's just extra code that is useless and confusing. Even when you log or convert, you end up rethrowing.
Realize that most of the time, you can NOT handle an exception. Truly. Many fail to grasp this. But the reality is, if you get an IOException reading or writing to the disk, game over. That request cannot be completed for the user. If your network is flaky and you can't talk to the database, same thing.
Rule #2. When you do get an exception that you cannot handle, the only thing you can do is try to fail in such a way that it is helpful to the user. This means, log it for later analysis (including original stack/cause), and then report something as helpful as possible to the user. Clean up whatever you must, so that the system remains in a consistent state.
Given that this communication with the end user happens at a very high level, that means you usually have to catch at that level. Most of the time, I find that there is very little value in any exception handling between it's inception point and the top level where you catch it for logging and reporting to the user. I often convert to a form of RuntimeException, but that's only done to ease propagation through the layers.
The biggest and most important thing is to realize that you usually can't handle exceptions, so any code you write for them should be as simple as possible.
我不认为分层是一个纯粹的想法,以至于这会破坏它。
包装和重新抛出也不会增加太多价值。
让服务层处理异常有什么问题吗?那应该是防线的尽头,最后的防线。这种设计让服务可以一劳永逸地记录异常,并将用户友好的消息发送到 UI 进行显示。
I don't think layering is such a pure idea that this breaks it.
Wrapping and rethrowing doesn't add much value either.
What's wrong with having the service layer handle exceptions? That ought to be the end of the line, the last line of defense. This design lets the service log the exception - once and for all - and send a user friendly message to the UI for display.
您通常希望捕获调用堆栈中较高位置的异常,但仅限于有意义的程度。如果数据级别可以处理并记录异常,并且只需将消息传递回前端,那么这将使事情变得简单且更加灵活。
就我个人而言,如果我需要尝试和最后,那么我也想捕获并针对那里的情况做一些事情,而不是将其传递给调用者。请记住,良好的设计规则总是有例外的(通常是另一个规则,如 KISS)。
You generally want to catch exceptions higher in the call stack, but only to the point that is makes sense. If the data level can handle and log the exception and just pass a message back to the front-end then that will keep things simple and more flexible.
Personally, if I need to have a try and a finally then I would like to also catch and do something about the situation there rather than pass it up to the caller. Just keep in mind there are always exceptions to good design rules (normally another rule like KISS).
这里存在三个相互关联的问题。
首先,可以不断地重新包装异常,但是它提供了什么价值?您只是在原始异常周围创建更多层。仅当我可以提供有关异常的附加信息或第一个异常导致另一个异常时,我才会包装异常。
其次,异常的思想是响应某个功能无法正常完成。您应该在最适合处理问题的地方捕获异常。如果代码有“另一种选择”,则应在该点捕获异常。否则将其记录下来以供用户或开发人员解决。
第三,try/finally 块。当异常导致资源处于打开或分配状态时,这些非常有用。我总是使用 try/finally 来清理可能保持打开状态的资源(我最喜欢的是 java.sql 中的 Statement/ResultSet,它是一个巨大的内存消耗者)。一个真正优秀的程序员在他们的代码中包含很多这样的内容,作为一种优雅地恢复的方式,而不会造成巨大的内存泄漏或资源限制。
There are three interlocking problems here.
First, constantly re-wrapping exceptions can be done but what value is it providing? You are just creating more layers around the original exception. I only wrap an exception when I can provide additional information about the exception or when the first exception causes another.
Second, the idea of an exception is to respond that a function can not be completed normally. You should catch the exception at the place where it makes the most sense to deal with the problem. If the code has "another alternative" the exception should be trapped at that point. Otherwise log it for the user or developer to work out.
Third, the try/finally block. These are useful when an exception would cause resources to hang out in a open or allocated state. I always use try/finally to clean up resources that might be left open (my favorite is the Statement/ResultSet from java.sql, a huge memory hog). A really good programmer has a lot of this in their code as a way to recover gracefully without creating huge memory leaks or resource constraints.