当前位置: 首页> 房产> 市场 > 深圳宝安区天气预报_中国联通与腾讯设立合作_网站服务费一年多少钱_免费广告网

深圳宝安区天气预报_中国联通与腾讯设立合作_网站服务费一年多少钱_免费广告网

时间:2025/9/11 13:53:20来源:https://blog.csdn.net/qq_28194001/article/details/143093456 浏览次数:0次
深圳宝安区天气预报_中国联通与腾讯设立合作_网站服务费一年多少钱_免费广告网

需求说明

这次接到的一个需求,需要优化一个接收包裹号的接口。产品反馈最近客户方调用接口请求经常超时,需要我们优化,减少超时情况的发生。经过我们检查发现这是个已经运行了半年的旧接口,既然是最近才反馈,大概是数据量增长后导致的慢查询,接下来查看代码后也发现的确有这个原因,但除此之外,这段代码也有些坏味道,让我们一起分析分析(想直接知道哪四步看总结哦)。

现状描述

目的

接收客户的包裹数据集合,并记录包裹状态到我们的业务数据表,以供用户在界面上查看包裹信息的同时,能够看到包裹在客户方系统的状态,能及时关注到货物运输的进度。目前代码实现流程图如下所示

流程图

当前流程
通过上面的流程图,大家可能一眼就发现了其中的猫腻,让我们分析下问题在哪。

伪代码

public AjaxResult paStatus(List<PaStatusForm> paStatusList) {for (PaStatusForm form : paStatusList) {// 查询该包裹号是否属于我们系统PaInfo paInfo = paStatusMapper.selectPaInfo(form.getPaNo());if (paInfo == null) {return AjaxResult.error("包号不存在");}// 查询状态表中该包裹号是否存在,不存在则新增,存在则更新PaStatusDetail detail = paStatusMapper.selectPaStatusDetail(form.getPaNo());if (detail == null) {detail = new PaStatusDetail();detail.setId(getNextUniqueId(PaStatusDetail.class));detail.setBusinessId(paInfo.getId());detail.setPaNo(form.getPaNo());detail.setStatus(form.getStatus());paStatusMapper.insertPaStatusDetail(detail);} else {detail.setStatus(form.getStatus());paStatusMapper.updatePaStatus(detail);}}return AjaxResult.success();
}

发现问题

  1. 问题一:接收到的数据是一个数组/集合,程序每次处理都是逐个元素处理,每行数据都查询一次数据库;
  2. 问题二:查询检查,插入/更新糅合在一起,导致整个事务比较大,事务时间较长
  3. 问题三:再进一步,用户经常查询的数据,对于这个包裹状态的实时性是否硬性要求呢?

优化思路

  1. 针对问题一,我们优化下查询语句,将集合中的元素通过修改查询语句,将每100个包号拼接为IN查询,避免一个包号查询一次,减少数据库连接的次数;
  2. 针对问题二,我们将数据的查询检查和事务处理拆分。检查和数据查询整理应该和数据库写事务进行分离,在进行写事务操作时,走批量更新的方式,接口优化后的流程如下:
    问题1、2的优化流程:将数据库事务与校验拆分
    通过上述优化后,接口效率已经得到了很大的提升;
  3. 对于问题三,是否有必要呢?经过我们生产环境的“试验”(我也不想试验的,谁知道接口偶尔还是慢)来看是有的,经过日志监控,我们发现更新条件并不是主键,因此并发执行update时真的很慢,即使做了前两个问题的优化后,接口在大数据量的情况下响应时间依然很长。在跟产品了解了用户对于这个状态的实时性要求并不高,所以决定将接口逻辑和修改业务表的逻辑拆分,简化接口逻辑,修改为两个流程:
    问题3优化后的流程:将业务表的修改与接口逻辑拆分

伪代码

public AjaxResult paStatus(List<PaStatusForm> paStatusList) {List<TempPaStatusDetail> insertTempList = new ArrayList<>();// 每100个包号查询一次, 需要自己实现subPaNoList哦List<List<String>> subPaNoList = subPaNoList(paStatusList);List<PaInfo> existsPaInfos = new ArrayList<>();for (List<String> subPaNo : subPaNoList) {// 将存在的数据都放入集合中, 每100个包查询一次,减少查询次数,提高效率List<PaInfo> paInfos = paStatusMapper.selectPaInfos(subPaNo);if (paInfos.size() > 0) {existsPaInfos.addAll(paInfos);}}// 通过程序找到不存在的包if (existsPaInfos.size() != paStatusList.size()) {return AjaxResult.error("包号数据量不匹配,存在非法包");}// 只在插入逻辑开启事务控制AopContext.currentProxy().batchInsertPaStatusDetail(insertTempList);return AjaxResult.success();
}
@Transactional
public void batchInsertPaStatusDetail() {// 批处理代码实现...
}// 异步处理的代码逻辑也需自己实现喔。。。

通过上述优化后,接口响应时间都能保证在0.3秒内返回。

总结

  1. 这次的接口性能优化主要思路为以下四步,一般的接口优化通过这几步大体都能完成优化工作了:
    • 优化查询sql:提高数据校验,查询组装等逻辑的执行效率;
    • 避免频繁创建数据库连接:修改数据库时考虑能否执行批量处理的操作,因为创建数据库连接比较耗时;
    • 避免大事务:拆分检查组装数据和数据库事务,在修改数据库操作时才开启事务处理;
    • 简化逻辑,从接口中拆分出重业务逻辑,让接口执行的事情更轻量化。
  2. 由于我们系统没有接入消息队列,所以图中的待处理数据表流程流程图在我的系统中是通过每5分钟执行一次的定时器去完成的,如果你的系统有接入消息队列会更好,数据处理更及时,而不用等定时器到某个时间点时才一并去处理,除了降低应用的符合外,可能还能减少数据的堆积?

大家如果有什么更好的见解也可以互相交流哈。

关键字:深圳宝安区天气预报_中国联通与腾讯设立合作_网站服务费一年多少钱_免费广告网

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: