热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java事务异常处理_controller的异常处理以及service层的事务控制controller层处理异常还是service处理异常PS下...

JavaWeb中Service层异常抛到Controller层处理还是直接处理?大家一般在项目里,业务层的方法报错都会直接往上抛到控制层来做统一的处理&

JavaWeb 中 Service 层异常抛到 Controller 层处理还是直接处理?大家一般在项目里,业务层的方法报错都会直接往上抛到控制层来做统一的处理,一般来说,有经验的开发者会选择这样的异常处理方法吗?如果不这样做,那么一般怎样做?下面我们一起来学习下。

一般初学者学习编码和错误处理时,先知道编程语言有一种处理错误的形式或者约定(如Java就是抛异常),然后就开始用这些工具,但是却反过来忽视这个问题的本质:

处理错误是为了写出正确的程序

到底怎么算“正确”呢?是要由解决的问题决定的。问题不同,解决方案就不同。

比如,一个web接口接受用户的请求,这个请求需要传入一个参数“年龄”,也许业务要求这个字段应该是个0~150之间的整数。如果用护输入的是个字符串或者负数就肯定不被接受。一般在后端的某个地方都会做输入的合法性检查,检查不过就抛异常。但是归根到底这个问题的“正确”解决方法总是要以某种形式提示用户。而提示用户是某种前端工作,这就要看这个界面到底是app,H5 + ajax还是类似于jsp那样的服务器产生的界面。不管哪种,你需要根据需求去”设计一个修复错误“的流程。比如一个常见的流程需要后端抛异常,然后一路到某个集中处理错误的代码,将其转换为某个HTTP的错误(某个特定业务错误码)提供给前端,前端再去做”提示“。如果用户输入了非法的请求,从逻辑上后端都没法自己修复,这是个“正确”的策略。

换一个例子,比如用户想上传一个头像,后端将图片发给某个云存储,结果云存储报500错误。怎么办呢?你可能想到了重试几次,因为也许问题仅仅是临时的网络抖动而已,重试就可以正常执行。但如果重试多次无效。如果做系统时设计了某种热备方案,那么就可能改为发到另外一个服务器上。“重试”和“使用备份的依赖”都是“立刻处理“。

但如果重试无效,所有的备份服务也无效,那么也许就能像上面那样把错误抛给前端,提示用户“服务器开小差”。从这个方案很容易看出来,你想把错误抛到哪里是因为那个catch的地方是处理问题最方便的地方。一个问题的解决方案可能要几个不同的错误处理组合起来才能办到。

另外一个例子,你的程序抛了一个NPE。这一般就是程序员的bug——要不就是程序员想要表达一个东西”没有“,结果在后续处理中忘了判断是否为null;要不就是在写代码时觉得100%不可能为null的地方出现了一个null。不管哪种情况,这个错误用户总会看到一个很含糊的报错信息,这远远不够。“正确”的办法是程序员自己能尽快发现它,并尽快修复。要做到这一点,需要监控系统不断的爬log,把问题报警出来。而不是等到用户找客服来吐槽。

再换一个例子,比如你的后端程序突然OOM,挂了。挂的程序是没法恢复自己的。要做到“正确”就必须得在服务之外的容器考虑这个问题。比如你的服务跑在k8s上,他们会监控你程序的状态,然后重新启动新的服务实例以弥补挂掉的服务,还得调整流量,把去往挂掉服务的流量切掉,重新换到新的实例上。这里的恢复因为跨系统所以不能仅仅用异常实现,但是道理是一样的。但光靠重启就是“正确”的吗?如果服务是完全无状态的,问题不大。但是如果是有状态的,部分用户数据可能就会被执行一半的请求搞乱套。因此重启时要留意先“恢复数据到合法状态”。这又回到了你需要知道怎么样才是“正确”的做法。只依靠简单的语法功能是不能无脑解决这个事的。

我们可以推广下,一个工作线程的“外部容器“是管理工作线程的“master”。一个网络请求的“外部容器”是一个web server。一个用户进程的“外部容器”是操作系统。Erlang把这种supervisor-worker的机制融入到语言的设计中。

Web程序之所以很大程度上能够把异常抛给顶层,主要由于3个原因:

请求来自于前端,对于因为用户请求有误(数据合法性、权限、用户上下文状态)造成的问题,最终大概率只能告诉用户。因此抛异常到一个集中处理错误的地方,把异常转换为某个业务错误码的方法是合理的。

后端服务一般都是无状态的。这也是互联网系统设计的一般性原则。无状态就意味着可以随意重启。对于用户的数据因为下一条一般情况下不会出问题。

后端对数据的修改依赖DB的事务。因此一个改了一半的没提交的事务是不会造成副副作用。

但你要清楚上面这3条并不是总是成立的。总会存在一些处理逻辑并非完全无状态,也并不是所有的数据修改都能用一个事务保护。尤其要注意对微服务的调用,对内存状态的修改是没有事务保护的,一不留神就会出现搞乱用户数据的问题。比如:

42c371fcaa1ea4efc6c48250b225c817.png

先假设this.statusVar1, this.statusVar2, this.statusVar3之间需要维护某种不变的约束(invariant)。然后执行这段代码时,如果在doStep3那抛出一个异常下面对statusVar3的赋值就不会执行。这时如果不能将statusVar1和statusVar2的修改rollback回去,就会造成数据违反约束的问题。而程序员一般是很难直接发现这个数据被改坏了。而坏掉的数据可能会偷偷的导致其他依赖这个数据的代码逻辑出错(比如原本应该给积分的,结果却没给)。而这种错误一般非常难调查,从大量数据里找到不正确的那一小撮是相当困难的事。

比起上面这段更难搞得定的是这样的代码:

4bdceb049504b8c7930ffdc582736892.png

这段代码的可怕之处在于,你在写的时候可能会以为doStep1~3这种东西即使抛异常,也能被Controller里的catch。在svc这层是不用处理任何异常的,因此不写try……catch是天经地义的。但实际上doStep1、doStep2、doStep3任何一个抛异常都会造成svc的数据状态不一致。甚至你一开始都可以通过文档或者其他沟通方式确定doStep1、doStep2、doStep3一开始都是必然可以成功,不会抛错的,因此你写的代码一开始是对的。但是你可能无法控制他们的实现(比如他们是另外一个团队开发的lib提供的),而他们的实现可能会改成会抛错。你的代码可能在完全不自知的情况下从“不会出问题”变成了“可能出问题”…… 更可怕的是类似于这样的代码是不能正确工作的:

a6709fa6b30caf13a8d425eaadfe91cd.png

你可能以为这样就会处理好数据rollback了,甚至你会觉得这种代码非常优雅。但是实际上doStep1~3每一个地方抛错,rollback的代码都不一样。你必须得这么写:

2a5d1e4f7d22e7ed1708ca08e562bb65.png

这才是能得到正确结果的代码——在任何地方出现错误都能维护数据一致性。优雅吗?看起来很丑。这甚至比go的if err != nil还丑。但如果一定要在正确性和优雅性上作出取舍,我会毫不犹豫的选择前者。作为程序员是不能直接认为抛异常可以解决任何问题的,你必须学会写出有正确逻辑的程序,哪怕很难,并且看起来很丑。为了达成很高的正确性,你不能总是把自己大部分注意力放在“一切都OK的流程上“,而把错误看作是可以随便搞一下的工作,或者简单的相信exception可以自动搞定一切。

总结一下,我希望所有程序员对错误处理都要有起码的敬畏之心。Java这边因为Checked Exception的设计问题不得不避免使用,而Uncaughted Exception实在是太过于弱鸡,是不能给程序员提供更好地帮助的。

因此,程序员在每次抛错或者处理错误的时候都要对自己灵魂三击:这个错误的处理是正确的吗?会让用户看到什么?会不会搞乱数据?不要以为自己抛了个异常就不管了。

此外,在编译器不能帮上太多忙的时候,好好写UT来保护代码脆弱的正确性。



推荐阅读
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
author-avatar
mobiledu2402851203
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有