当前位置: 首页 > news >正文

在某服务中,两方法递归调用导致堆栈溢出

在某服务中,两方法递归调用导致堆栈溢出

服务层、service、方法、模块、增、查、insert、save、select、get

背景

这个问题已经过去一段时间了,而且当时反馈过来很快就改好了,但是如何在开发和维护阶段避免出现这种问题?有没有适用性原则或者规范?这个问题困扰了我许久,特此记录下来。

项目中的某服务原有 保存方法 中,调用了查询方法;在 查询方法 中,直接调用了dao层(mapper);

某次维护,保存方法未动,在没有阅读保存方法的逻辑的情况下,在查询方法中调用了保存方法,初上线时没有问题,直到一段时间以后,用户反映系统报错,无法保存。

问题描述

一、保存(兼有修改功能)方法的逻辑:
  1. 检查参数合法性
  2. 通过查询方法获取库中数据
  3. 若查询有数据,向要保存的map中填入id,否则填id=0
  4. 向map中装填其他字段
  5. 执行低一层保存方法(这个方法会按id查询,查询出数据则修改,否则执行新增)
二、维护前查询方法直接调用dao查了,但是新入需求需要本库可能没有的信息,需要加逻辑,修改为:
  1. 先查本数据库,有对应记录且有对应数据就直接返回(对应记录指某行,对应数据指该行某列)
  2. 本库没有对应数据,查外库,外库无数据就返回上一步查询结果
  3. 外库有数据,本库无记录,向空白记录填入数据,调用保存方法,然后重新查本库,返回
  4. 外库有数据,本库有记录,向该记录填入数据,调用保存方法
  5. 返回记录

查看在线系统的日志,发现 一、2二、3 直接出现递归调用,导致程序爆栈。

分析

一看日志我就觉得这肯定不是我写的,然而打脸来得太快,我一看版本提交记录,还真是我写的。只不过,不是一次性完成的这个bug,分了两次。

第一次,我完成了上文中的第一部分,保存,先查询,然后保存,第二部分只有数据库直接查询;
第二次,由于对接ca,其数据中身份证号而没有员工号,而本系统中恰好又没有身份证号,只好从另外的数据库中单独查询。

从外库单独查询本身没有问题,然而我考虑到每次打开页面查这么一大圈太消耗资源,而且会使本系统内无法直接查询用户的签名信息,提前优化了一下。

而正是这个优化,造成了本文的问题,我的优化就是,在本库单独再存一份数据,保存数据正好就调用了第一部分的代码,而这个保存代码,首先就会调用此处的查询代码,
在库中没有用户签名信息的时候,就会使得这两块方法递归调用,这便是问题的直接来源。

这个问题的根本原因,本人现分析有三点:

  1. 提前优化,本来查询接口只应该负责查询,出了bug改回以后,出现了负优化,这个的根本原因是第三点;
  2. 方法实现逻辑未查明,而直接调用,直接导致问题产生;
  3. 设计思路混乱,各接口职责不明确,(目前认为)保存方法是会调用查询接口的,不管是不是清楚保存逻辑(第二点),而查询方法就不能在内部调用保存接口,应该在查询的调用位置保存,这是导致维护出问题的根本原因。

对上述原因,~~尚未找到适用规范或原则,~~现认为:

  1. 实现优先,以功能效果的实现为第一优先级,可以考虑代码改动或优化的可能性,可以留有一定改动余地,但不要直接实现处理业务逻辑以外的代码;
  2. 调用接口前,在不能保证接口的实现充分稳定可靠(起码无设计缺陷,没有明显bug)的情况下(其实第一块代码没问题,是维护出了问题),要阅读接口实现的源码;
  3. 对于数据库的增删改查,查不可调用增删改接口,删可调用查接口,增可调用查接口,改可调用查,也可调用删增接口(在阿里规范中不推荐使用删增实现改功能,对binlog不友好)

其实,我不需要找任何的规范,早在若干年前我就学过这个知识了!

这段bug代码,本来写得没有问题,是后来维护出了问题,
违反了面向对象的若干基本原则:

  1. 开闭原则:代码对扩展开放对修改关闭,在没有出bug的情况下,修改原来的查询逻辑,违反了这一原则,应该另起一个方法
  2. 单一职责:本身这个方法的查询功能已经够复杂了,我又增加了保存逻辑,功能不单一了,

解决方案

解决方案很简单,方法有二:

  1. 二、3中调用保存方法的部分注掉,直接新建个空白记录,装填数据返回即可;
  2. 将后来维护新增的代码放到一个新方法中,用新方法调用老方法实现功能,同时能避免未知bug。

重点在于分析,注意结合基本原理,避免以后再出现类似的问题。

声明:本文使用八爪鱼rpa工具从gitee自动搬运本人原创(或摘录,会备注出处)博客,如版式错乱请评论私信,如情况紧急或久未回复请致邮 xkm.0jiejie0@qq.com 并备注原委;引用本人笔记的链接正常情况下均可访问,如打不开请查看该链接末尾的笔记标题(右击链接文本,点击 复制链接地址,在文本编辑工具粘贴查看,也可在搜索框粘贴后直接编辑然后搜索),在本人博客手动搜索该标题即可;如遇任何问题,或有更佳方案,欢迎与我沟通!

相关文章:

  • 【第十六章:Sentosa_DSML社区版-机器学习之生存分析】
  • “投其所招”-智能投标领军者丨OPENAIGC开发者大赛高校组AI创作力奖|
  • 基于RepLKNet31B模型在RML201610a数据集上的调制识别【代码+数据集+python环境+GUI系统】
  • Rust 全局变量的最佳实践 lazy_static/OnceLock/Mutex/RwLock
  • # linux从入门到精通(三)
  • UDP通信
  • [数据结构] 二叉树题目 (二)
  • 阿博图书馆管理系统:SpringBoot技术应用
  • c语言中的杨氏矩阵的介绍以及元素查找的方法
  • django drf 分页器
  • MP4 格式:前世今生与技术解析
  • HarmonyOS鸿蒙系统开发应用程序,免费开源DevEco Studio开发工具
  • 高级前端进阶:揭秘 MemFire Cloud 的强大助力
  • python和pyqt-tools安装位置
  • pyside6与协程
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • css布局,左右固定中间自适应实现
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • js数组之filter
  • MD5加密原理解析及OC版原理实现
  • MQ框架的比较
  • nfs客户端进程变D,延伸linux的lock
  • orm2 中文文档 3.1 模型属性
  • Redux系列x:源码分析
  • SpiderData 2019年2月23日 DApp数据排行榜
  • use Google search engine
  • 仿天猫超市收藏抛物线动画工具库
  • 关于Flux,Vuex,Redux的思考
  • 关于使用markdown的方法(引自CSDN教程)
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 用mpvue开发微信小程序
  • 用Visual Studio开发以太坊智能合约
  • ​Linux·i2c驱动架构​
  • ​浅谈 Linux 中的 core dump 分析方法
  • #微信小程序(布局、渲染层基础知识)
  • %@ page import=%的用法
  • (003)SlickEdit Unity的补全
  • (20)docke容器
  • (javascript)再说document.body.scrollTop的使用问题
  • (STM32笔记)九、RCC时钟树与时钟 第一部分
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (三)模仿学习-Action数据的模仿
  • (四) Graphivz 颜色选择
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .NET应用UI框架DevExpress XAF v24.1 - 可用性进一步增强
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • .pyc文件是什么?