一个线上Java空指针问题的排查经过
某天,运营反馈,某商品下单异常
1.原来是一个空指针报错
根据用户输入的下单关键信息搜索日志系统看到如下报错
stackTrace: "java.lang.NullPointerException
at com.auto.order.service.utils.OrderingUtils.buildParentOrderData(OrderingUtils.java:194)
at com.auto.order.service.cart.impl.OrderingCommonServiceImpl.handleStat(OrderingCommonServiceImpl.java:1221)
at com.auto.order.service.cart.impl.OrderingIndexServiceImpl.receive(OrderingIndexServiceImpl.java:1027)
at com.auto.order.service.impl.OrderApiServiceImpl.receive(OrderApiServiceImpl.java:1979)
at com.auto.order.site.controller.neworder.OrderingIndexController.receive(OrderingIndexController.java:368)
原来是个空指针错误,来看下194行代码是啥
1 parentOrderData.setRefCookie(orderingReceiveParamBo.getRefCookie());
2 parentOrderData.setCityId(orderingReceiveParamBo.getRuleCityId().intValue());//194行
3 parentOrderData.setSessionId(orderingReceiveParamBo.getSessionId() != null ? orderingReceiveParamBo.getSessionId() : "");
上面代码块第二行就是原文件里194行,判断得出应该是ruleCityId字段为空导致了空指针异常;又看了下parentOrderData对象和orderingReceiveParamBo对象的ruleCityId字段都是Integer类型,这里没有必要intValue,改之如下
2 parentOrderData.setCityId(orderingReceiveParamBo.getRuleCityId());//194行
上线后,以为问题就解决了呢,谁知依旧报错,继续翻看日志,发现如下报错
--- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'city_id' cannot be null
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:102)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
2.看来不仅仅是一个空指针
数据库里设置了city_id字段是非空的,但是程序没有获取到city_id,为啥获取不到呢,继续排查city_id是怎么获取的
/**
* 获取所在城市
*/
public static int mallCityId(HttpServletRequest request){
try {
String ck = getCookieValue(request.getCookies(), "cookieCityId");
if ( "999999".equals(ck)) {
return 110100;
}
if (StringUtils.isNotBlank(ck) && Integer.parseInt(ck) > 0) {
return ck.indexOf("9999") > 0 ? Integer.parseInt(ck.substring(0, 2) + "0100") : Integer.parseInt(ck.substring(0, 4) + "00");
}
ck = getCookieValue(request.getCookies(),"area");
if ("999999".equals(ck)) {
return 110100;
}
if (StringUtils.isNotBlank(ck) && Integer.parseInt(ck) > 0) {
return ck.indexOf("9999") > 0 ? Integer.parseInt(ck.substring(0, 2) + "0100") : Integer.parseInt(ck.substring(0, 4) + "00");
}
} catch (Exception e) {
indexLog.error("mallCityId is error!",e);
}
return 110100;
}
代码中city_id是从cookie中获取的,但是这一段代码返回结果不可能为null,即使有异常,也该返回默认城市110100!继续看哪里调用了这个方法,原来是在拦截器方法里调用了这个方法取各种cookie,并做容错处理,主要代码如下
/**
* 方法执行前的拦截方法
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String sessionId = "";
Long pvId = 0L;
Long positionId = 0L;
Integer cityId = 0;
String sessionVid = "";
String refCookie = "";
String sessionIp=""; Long s = System.currentTimeMillis();
try {
sessionId = getCookieValue(request.getCookies(),"sessionid");
sessionVid = getCookieValue(request.getCookies(),"sessionvid");
sessionIp = getCookieValue(request.getCookies(),"sessionip");
pvId = Long.valueOf(StringUtils.isNotBlank(getCookieValue(request.getCookies(), "mpvareaid")) ? getCookieValue(request.getCookies(), "mpvareaid") : "0");
positionId = Long.valueOf(StringUtils.isNotBlank(getCookieValue(request.getCookies(), "autohomeareaid")) ? getCookieValue(request.getCookies(), "autohomeareaid") : "0");
cityId = mallCityId(request);
request.setAttribute(CUR_SESSION_ID,sessionId);
request.setAttribute(CUR_SESSION_IP,sessionIp);
request.setAttribute(CUR_SESSION_VID,(sessionVid == null?"":sessionVid));
request.setAttribute(CUR_REF_COOKIE,(refCookie == null?"":refCookie));
request.setAttribute(CUR_PV_ID,pvId);
request.setAttribute(CUR_POSITION_ID,positionId);
request.setAttribute(CUR_CITY_ID,cityId);
request.setAttribute(PARTNER, getCookieValue(request.getCookies(), PARTNER));
request.setAttribute(CURR_UNIX_TIME, System.currentTimeMillis());
} catch (Exception e) {
log.error("get interceptor error:", e);
}
timeLog.info("interceptor end timecost=======>"+(System.currentTimeMillis()-s));
return true;
}
这个拦截器方法,粗看下去没有发现任何问题,如果这个方法有异常,但是日志系统死活没有看到catch打印的error堆栈信息;如果没异常,按流程走下来,cityId字段不可能为空啊!怎么办,笨方法,加日志,我把这个方法调用 mallCityId 方法之上每隔一行都加了日志,看哪行有猫腻
通过加日志定位到了问题所在,上面代码块的第18行一直走不到,18行就是这个
pvId = Long.valueOf(StringUtils.isNotBlank(getCookieValue(request.getCookies(), "mpvareaid")) ? getCookieValue(request.getCookies(), "mpvareaid") : "0");
仔细看这一行,真有可能出了问题,如果从cookie里取出来的不是数字,还要 Long.valueOf 肯定就报错了,But为啥捕获不到异常,再看catch块log打印到哪里了
private static Logger log = LoggerFactory.getLogger(CommonInterceptor.class);
private static final Logger timeLog = LoggerFactory.getLogger("creat-order-time");
private static final Logger indexLog = LoggerFactory.getLogger("access-index");
log对应的是 CommonInterceptor.class ,但是log4j2.xml文件里并没有配置这个类文件,其他两个日志文件在log4j2.xml文件里都有配置,唯独这个CommonInterceptor.class 没有映射,那日志打印到哪里了呢?最后在tomcat的catalina.out文件看到了报错

上图报错行,正好对应的就是拦截器里第18行,从cookie里取出来的mpvareaid是undefined,所以类型转换就报错了,但是由于缺少log4j日志配置,没有在常规业务日志路径捕获到该异常。最后把业务日志路径改了,兼容了undefined情况,问题最终解决
3.总结两点
第一:未兼容从cookie里取出来的异常数据undefined
第二:日志打印不规范,没有合理配置日志路径
一个线上Java空指针问题的排查经过的更多相关文章
- Linux(2)---记录一次线上服务 CPU 100%的排查过程
Linux(2)---记录一次线上服务 CPU 100%的排查过程 当时产生CPU飙升接近100%的原因是因为项目中的websocket时时断开又重连导致CPU飙升接近100% .如何排查的呢 是通过 ...
- 一次线上CPU高的问题排查实践
一次线上CPU高的问题排查实践 前言 近期某一天上班一开电脑,就收到了运维警报,有两台服务CPU负载很高,同时收到一线同事反馈 系统访问速度非常慢,几乎无响应. 一个美好的早晨,最怕什么就来什么.只好 ...
- 线上CPU飙升100%问题排查
本文转载自线上CPU飙升100%问题排查 引子 对于互联网公司,线上CPU飙升的问题很常见(例如某个活动开始,流量突然飙升时),按照本文的步骤排查,基本1分钟即可搞定!特此整理排查方法一篇,供大家参考 ...
- 01 . Go之Gin+Vue开发一个线上外卖应用
项目介绍 我们将开始使用Gin框架开发一个api项目,我们起名为:云餐厅.如同饿了么,美团外卖等生活服务类应用一样,云餐厅是一个线上的外卖应用,应用的用户可以在线浏览商家,商品并下单. 该项目分为客户 ...
- 一个线上JVM的CPU资源占用过高问题的排查
原文:https://www.iteye.com/blog/tyrion-2293369 上午线上某应用的一台JVM的CPU占比突然飙高到192%,并且一直下不来,导致监控一直告警,好久没处理这种问题 ...
- 线上Java程序占用 CPU 过高,请说一下排查方法?
我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...
- 一个线上 Maven 诡异问题排查过程
å. 前言 现在的大部分 Java 应用基本都是通过 Maven 进行组织的,不论是分布式应用还是单体集群应用往往都会通过一个 父 POM 加若干子 POM 完成项目的组织.然而这种多应用多模块的拆分 ...
- 一则线上MySql连接异常的排查过程
Mysql作为一个常用数据库,在互联网系统应用很多.有些故障是其自身的bug,有些则不是,这里以前段时间遇到的问题举例. 问题 当时遇到的症状是这样的,我们的应用在线上测试环境,JMeter测试过程中 ...
- 一次性搞清楚线上CPU100%,频繁FullGC排查套路
“ 处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及 Full GC 次数过多的问题. 当然,这些问题最终导致的直观现象就是系统运行缓慢,并且有大量的报警. 本文主要针对系统 ...
随机推荐
- Raft Paper 简译
本文是对 Raft Paper 核心部分的意译,不包括原文中的如下章节:<3 Paxos 的优缺点论述>.<4 Raft 的易理解性介绍>.<9 Raft 算法的易理 ...
- Jmeter 使用技巧 (如何在linux下运行jmeter视窗界面呢)-jmeter如何模拟http发送gzip数据
jmeter如何模拟http发送gzip数据 有时候我们需要模拟在客户端将数据压缩后, 发送(post)到服务器端. 通常这种情况,会发生在移动终端上. 这样做的好处, 是可以节省流量. 当然, 服 ...
- Cocos2d-x之Sprite
| 版权声明:本文为博主原创文章,未经博主允许不得转载. Sprite是Cocos2d-x游戏开发者最常用的类,用图片把精灵(Sprite)显示在屏幕上. 在游戏开发中,经常会遇到精灵(Sprit ...
- CentOS中svn的搭建
1:使用yum源进行安装 # rpm -qa subversion //检查是否自带了低版本的svn #yum remove subversion //卸载低版本的svn #Yum install s ...
- 图推荐-基于随机游走的personrank算法
转自http://blog.csdn.net/sinat_33741547/article/details/53002524 一 基本概念 基于图的模型是推荐系统中相当重要的一种方法,以下内容的基本思 ...
- HDU2732 Leapin' Lizards
Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- java反射-学习
使用Java反射机制可以在运行时期获取Java类的信息,可获取以下相关的内容: Class对象 类名 修饰符 包信息 父类 实现的接口 构造器 方法 变量 注解 简单的反射例子: 1.获取class对 ...
- openface人脸识别框架
openface的githup文档地址:http://cmusatyalab.github.io/openface/ openface的安装: 官方推荐用docker来安装openface,这样方便快 ...
- 灵活轻便的Table控件,适合复杂样式的内容排版
github仓库地址 https://github.com/gaoyangclub/GYTableViewController 前言 TableView是在项目开发的时候经常用到的组件,几乎百分之八十 ...
- Spring Bean 的加载过程
Spring Bean 的加载过程 一个是populateBean,一个是initializeBean,这两个方法完成了bean的赋值与初始化. 这里有一个BeanDefinitionValueRes ...