Java 项目公共库文件,如何使用异常

2015-11-13 10:15:02 +08:00
 odirus
相关节点: /t/235506 ,昨天在这个帖子里面请教了各位 V 友如何解决多项目共同依赖某个组件的问题,非常感谢,也让我学到了很多方案,非常感谢。最后我使用的方式是把数据库层打包成一个 maven 库文件,供其他项目调用(我本人也更倾向于 RPC ,不过时间上来不及)。

今天要请教的问题是,在打包的这个公共库文件中,主要是操作 MyBtis ,会抛出运行时异常,其中 MyBatis 抛出的所有异常基类是 org.apache.ibatis.exceptions (参考链接 http://tool.oschina.net/apidocs/apidoc?api=mybatis-3.1.1 ),作为公共库文件,我要自己新建一个异常来表示我调用这个公共库时的所有异常吗(也就是把数据库操作的所有异常封装成为该库文件的自定义异常)?还是抛出被使用库的异常基类比较合适呢?

追加:再仔细看了该 API 文档,其异常基类已经是属于 Deprecated ,全部异常采用一个工厂类包装后抛出,也就是说我每次操作数据库需要捕获两个子类异常( PersistenceException, TooManyResultsException )?还是有更好的方式呢?

以前这种情况我直接通过 Exception 来捕获,所以所有异常都能够获得,但是最近看了很多书,这是严重的错误思想,所以希望能够得到更好的建议。

谢谢大家
2602 次点击
所在节点    Java
12 条回复
beneo
2015-11-13 10:30:53 +08:00
Checked Exception ,也就是你一个业务流转的方式,比方说,如果你有事务超时的异常的时候,你会发消息给到你的监控,等等,这时候你自己要 catch 住,这是你要 hold 住的地方,然后再 Runtime 出去。

我认为任何异常都应该最后 throw 出去

但是大部分作为一个公共组件,特别是内部使用的时候,也就是你用一下我的 SQL ,他也需要用一下这个 SQL ,我就打个包给大家用。我就建议全部变成 Runtime Exception 吧。

为什么这么说?

异常比方说:
索引问题
SQL 语句问题
事务锁超时等等

这一系列都属于 BUG ,这类 SQL 本来就不应该在代码中出现,也不是你的使用方,或者叫做业务方,他们需要关心的。出现了异常,就去修吧,把 log 打到单独的文件里面。

此外, 还有一些通用的规范,比方说
数据 insert or update ,更新成功返回 1 ,没有成功返回 0
findOne ,找到返回 obj ,没有找到 返回 null
findList , 没有找到返回 empty list ,绝对不能成为 null

我注意到你在用 mybatis ,我十分推荐你使用 MyBatis Generator ,这样可以帮助你少写很多代码。

最后,我是 Hibernate 的忠实粉丝,谢谢
odirus
2015-11-13 10:31:03 +08:00
补充: PersistenceException 是 TooManyResultsException 的父类,所以我可以捕捉这个异常,我不仔细造成的。
但麻烦提出更好的异常处理方式,昨天看了《 Effective Java 》中异常部分后很有感触,希望能得到更多的实战经验指导。
odirus
2015-11-13 10:39:20 +08:00
@beneo 感谢你这么细致的回答,有所感悟了。但我还有点疑惑,如果把 Sql 语句错误等库开发者引入的异常划分到 RuntimeException 的话,那调用方很容易就会忽略这个异常,也就是他没有强制对异常进行捕获,容易导致对方忽略这个异常。

假如我现在就是库的使用方,知道对方有运行时异常,那我应该在 API 调用的地方主动捕获呢?还是放任不管,在总入口捕获所有运行时异常呢?
wizardforcel
2015-11-13 10:44:35 +08:00
@odirus 能处理的异常当场处理,不能处理的异常在控制层的入口捕获。
beneo
2015-11-13 10:47:52 +08:00
@odirus 你说的两个问题,我感觉可以一起来讲

CheckedException 出来,就像你说的,业务方(上层调用者)需要知道有可能出现这个异常,你需要做下一步处理。

但是实际情况是,上层调用者很少去关心这个很可能出现的异常,因为还有上层,一个 Service 里面调用很多个 DAO 嘛。不过这个要具体的看你们的业务。


再说如何处理所有类型的 Exception ,比方说现在很多 App 或者 Web 后台都是接入 Java 的,我当然不希望我的异常被用户感知到,那现在的容器都有一个全局 Catch Exception 的功能, Spring 有, Jersey 有, Spring boot 有, Grails 都有。我们会利用这个功能 Catch 所有 Exception ,返回 App 能理解的 JSON (比如网络异常请稍后再试)或者 Web 直接跳转到 500 页面,并消息通知给开发者。
SoloCompany
2015-11-13 10:56:35 +08:00
Checked Exception 是 Java 里面的一个大毒瘤
odirus
2015-11-13 10:57:26 +08:00
@beneo 恩,谢谢哈,现在又理解得更深入了。我是动态语言转到静态语言来的, 以前没有系统地使用过,都是想到哪儿,用到哪儿,不具有基本的开发素质。现在特别喜欢这种工业级语言,开发的时候有章可循,而不是发挥自己的脑洞,现在反而有点不太喜欢 C 系列的其他脚本语言,个人观点。

另外我也比较喜欢 hibernate ,以前在其他语言里面我实现过这种思想的工具,不过还是没有 Java 好用。

总之,非常感谢。
odirus
2015-11-13 10:57:58 +08:00
@SoloCompany 何以见得?请阐明高见,谢谢
SoloCompany
2015-11-13 11:09:31 +08:00
@odirus 只是一个观点,你可以同意或者不同意,从使用经验来说,绝对是给 API 以及接口设计带来无数的麻烦,而好处基本上可以忽略,扔两篇文章供参考
http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/
http://blog.philipphauer.de/checked-exceptions-are-evil/
tonyVex
2015-11-13 11:14:30 +08:00
借个楼 @beneo , Hibernate 中,原来的业务是物理删除,假设一对多 删除掉一的一方同时级联删除掉多的一方,这个是没有问题的。 现在要改为逻辑删除,删除的时候改为更新,即同时更新一和多的某一个字段如更新 stauts 的。 由于很多删除的地方,怎么改最方便呢。 可以通过配置文件级联更新 stauts 字段吗?
odirus
2015-11-13 11:36:06 +08:00
@SoloCompany 谢谢,均已拜读,第二篇印象更加深刻,谢谢推荐这么好的博文。
odirus
2015-11-13 13:36:38 +08:00
@SoloCompany 现在看了一下很多优秀设计的 API 都是采用的 RuntimeException ,比如 MyBtis 、 Jedis

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/235849

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX