那些年,我们写过的低级BUG,警钟长鸣
又一个低级的生产BUGif(newDto.getStoreName().equals(oldDto.getStoreName())newDto.getStoreCode().equals(oldDto.getStoreCode())newDto.getGoodsName().equals(oldDto.getGoodsName())newDto.getGoodsSpec().equals(oldDto.getGoodsSpec())newDto.getStallName().equals(oldDto.getStallName())newDto.getUnitName().equals(oldDto.getUnitName())){//不更新}else{updList.add(newDto);}问题是没有对属性null做判断导致NPE。修改后的代码if(Objects.equals(newDto.getStoreName(),oldDto.getStoreName())Objects.equals(newDto.getStoreCode(),oldDto.getStoreCode())Objects.equals(newDto.getGoodsName(),oldDto.getGoodsName())Objects.equals(newDto.getGoodsSpec(),oldDto.getGoodsSpec())Objects.equals(newDto.getStallName(),oldDto.getStallName())Objects.equals(newDto.getUnitName(),oldDto.getUnitName())){//不更新}else{updList.add(newDto);}java.util包都提供这个工具类了还有什么不用起来的理由出这种问题太他妈丢人了写的时候是咋想的啊又一个低级的生产BUGpublicstaticMultiPriceInfogetMultiPriceInfo(ListMultiPriceInfomultiPriceInfos,Stringcode){if(CollectionUtils.isEmpty(multiPriceInfos)){returnnull;}for(MultiPriceInfopriceInfo:multiPriceInfos){if(priceInfo.getPriceCode().equals(code)){returnpriceInfo;}}returnnull;}问题1 作为一个public方法没有校验参数code。问题2. priceInfo.getPriceCode().equals(code)可能会抛出NPE因为priceInfo.getPriceCode()可能会返回null。修改以后的代码publicstaticMultiPriceInfogetMultiPriceInfo(ListMultiPriceInfomultiPriceInfos,Stringcode){// 增加对code的校验if(CollectionUtils.isEmpty(multiPriceInfos)||StringUtils.isEmpty(code)){returnnull;}for(MultiPriceInfopriceInfo:multiPriceInfos){// 前面已经确保了code不是nullif(code.equals(priceInfo.getPriceCode())){returnpriceInfo;}}returnnull;}两个修改点增加对入参code为空的校验。改为code.equals(priceInfo.getPriceCode())。就因为这个小小的问题从凌晨0点搞到将近3点就是找不到问题在哪对代码还是有敬畏之心不能太随意安安稳稳躺床上睡觉它不香吗还有一点如果是异步执行一定要在异步方法的最外层加一个try-catch-finally进行兜底否则全局异常拦截器拦截不到再没有catch的话就只能进shell看日志了就怕没有shell的权限又一个低级的生产BUG上周五生产环境的二维码下载功能开始频繁报警看了下代码下载二维码这个功能服务端提供了2个接口一个是生成二维码的压缩包放到tomcat的临时目录里面然后第二个是下载接口现在的问题是第一个接口没问题第二个接口报的NPE。第二个接口非常简单就是读取文件写到respoonse里面如果NPE那就只有一个可能那就是下载的文件不存在。并且这个接口有一定概率报错还不是必现的我只好猜测因为下载的文件是存放在临时目录是不是因为系统硬盘空间不足而被系统删除了但是本地怎么也模拟不出来在这个方面浪费了大量的时间还是没找到一点头绪幸亏系统有全链路监控日志后来仔细观察日志才发现是异常是在一个Aop的拦截器里面抛出来根本不是业务代码抛出来的它是这么写的AspectComponentpublicclassLogApiAdvice{Around(annotation(org.springframework.web.bind.annotation.RequestMapping))publicObjectdoAround(ProceedingJoinPointjoinPoint)throwsThrowable{try{ObjectresultjoinPoint.proceed();if(result.getClass().isAssignableFrom(ApiResult.class)){....}else{....}returnresult;}catch(Throwablethr){....throwthr;}}}我们的下载的接口是这样的ApiOperation(下载二维码)RequestMapping(value/downCodeZip)publicvoiddownCodeZip(HttpServletResponseresponse,StringzipFilePath){}很显然方法的返回值是null因此在aop里面就发生了NPE很低级的一个失误导致生产不停报警最终代码回滚写代码还是得注意啊修改方法签名导致的bug有一个方法原先是返回Integer此方法在多个地方被调用改的时候改成了返回String自测通过junit也正常但是上生产报错了按道理说只要方法签名名改了所有调用的地方应该编译就报错啊操蛋的是项目使用了MapStruct背后自动把String又转成了Integer所以编译完全没问题但是一旦返回null就炸了。结论修改方法一定要全局检索调用的地方不要仅仅依赖编译器。