前言
本人小菜一枚,这个错误最终虽然是找到并解决了,但是现在仍然没有完全明白是为什么?问了问其他的同事也没具体定位到问题的本质,不过我仍然认为有记录的必要性。技术上没找到这个问题的根源,项目开发上是知道为什么会产生这个问题的!先不说太多,先把这个犯错和解决错误的具体情况记录下来,也好为以后避免这样的错误而积累点小小的经验!
事源
此列表是我们的应用所对应的环境,具体如下所示:
软件环境 | 开发环境 | 测试环境 | 生产环境 |
操作系统 | windows2003 | ||
Web服务器 |
tomcat6 |
weblogic | |
数据库 | oracle 10g | oracle 10g | oracle 10g |
事情是这样的,前一段日子我们做的一个项目,已经上线用户也一直在用,不过在使用的过程中出现一个比较奇怪的问题(出问题的地方是一个和文件的上传下载功能相关的模块)该功能模块总是时不时的出现一些问题,但是在开发环境和测试环境上却是好好的,生产环境用户一直在用着不能白天停下来查错,但是必须尽快的将问题解决否则只要用户一使用对应的功能就会产生错误---要上传的文件上传失败。
我首先想到的原因可能是发布的问题,我们专门发布的同事采用的是增量式的发布,有些文件生产环境和开发环境可能没有完全同步,于是当天晚上我们重新发布了一版新的应用,并且用Admin用户登录测试了一下对应的功能,没问题了,很高兴就回去了!如果问题就这么容易解决了,我的印象可能就不会这么深刻也没有记录的必要性了!第二天用户反馈说仍然有问题(我在客户现场上班)不对还要继续的查找,于是当天晚上我和那位发布应用的同事,开始逐步的查找到底那里出问题了!
程序出问题是很正常的,也是不可避免的!关键是想不通为什么在开发环境下没问题,在测试环境也没问题,在生产环境上也不是总是有问题,时而正常时而又不正常!我常说“找到问题产生的原因等于解决了一半的问题”,在项目开发中或者其他的情况下最怕这种不报错、不抛错、在开发环境正常在生产环境下时而正常时而又有问题的错误了,无从下手,当然主要还是自己比较菜的缘故!
现在就大络的认为是有由于系统环境的问题造成了此错误,不过排查还是要的,不能容忍这样的错误存在!我们仔细的查看了weblogic服务器运行的日志文件,以期能够找到引起问题的原因!功夫不负有心人,找到了---在日志中有一句插入语句没有执行(我们的文件上传是一种多对多的关系,需要往多个表中插入记录)。于是在自己的电脑上找到对应的程序段,来回检查了一下,没有发现有什么错误,让同事也看了一下,也没看出有什么错,不过在我的Action类中的具体的方法中即用try...catch捕获错误又用throws将错误往上抛出交给上一层的程序来处理,同事认为有问题于是去掉throws部分---重新编译此文件---从开发的服务器上找到编译好的文件---拿到生产环境发布---重启应用---测试---还是有问题---查看日志文件---和上次的情况一样依旧不报错!于是重复上述的操作,只是这次在对应的代码段中加上了若干条的输出语句,看看到底走到里不走了,使用这种方式再细化一下,最后终于找到走到那一句不走出问题了,不过下面就非常奇怪了因为怎么查也查不出不走的那个一句那里出问题了(是一段公共的且非常简单的程序)然后用同样的方式继续往那一句的方法中跟进,仍然没理出头绪来,看看时间十一点已过没办法,明天还得继续上班明天继续吧!
第二天一上班用户就问问题解决没。。。。。。
于是乎,当天晚上我们计划继续搞而且下定决心,找不到问题解决不了问题就不走了!工作的热情值得嘉奖,不过如果方向错了越努力错的就会越远!下午下班时,我们提前买上了点吃的,基本上按照昨晚的方式更加细化的又走了几边,在十二点的时候头都昏了!想走又不甘心,当天晚上的风比昨天的更大,只听见忽忽的拍打着玻璃的巨响,貌似在嘲笑我们“瞧瞧,这两个笨蛋这两天都是干了些什么?一个非常简单的错误到现在还没解决!”我可怜的同事,就这样陪着也遭了罪,我们都有些想回去了,不过如果今晚解决不了明晚又得继续(离周末还有两天呢!),再查查看如果还是没找到问题的所在就回!不过,我左想右想就是想不通,为什么不报错?为什么不抛错哪?程序在开发、测试、生产是一模一样的就环境不同,但是开发和测试都正常,生产上又不能调试,好犯难!
起来看看同事玩的啥游戏,走走动动,从头到尾再看一遍,就当我重新开发那!这次当看到对应的模型类时突然间灵光一闪,我终于知道,我错在哪里了?
错误
我们的项目文件结构大概如下所示,下面只是一个功能模块的事例
src.com.ca.agent
action//Action类文件包
dao//Dao文件类包,dao包下直接放的是我们手工写的
mapper//mppper包下的由mybatis自动生成器自动生成的,对应单表的增删改查都有
model //Model文件类包,model包下直接放的是我们手工写的,为了扩展开中发需要的模型类
mybatis//mybatis包下面的由mybatis自动生成器自动生成的,根据数据库中的表自动生成
service//Service文件类包,service包下直接放的是服务的接口类
impl//impl包下直接放的是服务的实现类
最终发现关于文件上传下载的那个关系表的模型有两个,model包下面有一个,mybatis包下面也有一个在上面的java类包中用到的全是com.ca.agent.model包下面的,不过在mybatis生成器自动生成的和数据库交互的映射文件中以及对应的Dao接口类中却是用的
com.ca.agent.model.mybatis包下面的!当然他两的属性和方法完全一样,只是在不同的包下面而已!问题应该就在这里了,找到问题下面的事情就比较简单了,将他们变成统一的应该就能把这个问题彻底的解决了!我选择将com.ca.agent.model包下面的模型类删掉,程序中用到的全部换成com.ca.agent.model.mybatis包下面的!
重新发布后问题果然彻底消失了!这两天印象颇深,现在还记得很清楚,问题总算搞定,当然更深层的问题还没解决?
始终没弄明白,为什么在生产环境下时好时坏?而在开发、测试上则一直没问题?还有就是为什么不报错?
下面是部分事例代码(引起问题的部分代码,仅示意一下),以做提醒避免下次犯同样的错误!
1:上面的java类包中除了mybatis生成器自动生成的部分,用到的FileAgent类全部引自com.ca.agent.model包
package com.ca.agent.dao; import org.mybatis.spring.support.SqlSessionDaoSupport; import com.ca.agent.model.FileAgent; /** * @说明:代理人文件管理 * @author godtrue * @修改时间:2014-01-09 */ public class FileAgentDao extends SqlSessionDaoSupport{ /* * 增加 */ public void insert(FileAgent fileAgent){ this.getSqlSession().insert("com.ca.agent.dao.mapper.FileAgentMapper.insert", fileAgent); }
2:下面是一个mybatis生成器自动生成的一个Dao接口类的部分代码,类中的FileAgent类引自com.ca.agent.model.mybatis包
package com.ca.agent.dao.mapper; import com.ca.agent.model.mybatis.FileAgent;
public interface FileAgentMapper {
/** * This method was generated by MyBatis Generator. * This method corresponds to the database table SALES.FILE_AGENT * * @mbggenerated Thu Jan 09 18:38:38 CST 2014 */ @Insert({ "insert into FILE_AGENT (AGENT_CODE_ID, FILE_ID, ", "FILE_TYPE_ID, IATA_CODE, ", "OPERATOR, OPERAT_IDENTIFY, ", "LAST_UPDATE_DATE)", "values (#{agentCodeId,jdbcType=DECIMAL}, #{fileId,jdbcType=DECIMAL}, ", "#{fileTypeId,jdbcType=DECIMAL}, #{iataCode,jdbcType=VARCHAR}, ", "#{operator,jdbcType=VARCHAR}, #{operatIdentify,jdbcType=DECIMAL}, ", "#{lastUpdateDate,jdbcType=TIMESTAMP})" }) int insert(FileAgent record);
后话
这个错误,现在我只能说和程序运行的环境有关,但是再具体是为什么就不清楚了,有待进一步的查证!不过为什么会出现上面的情况哪?为什么会出现在一个项目开发中同一张表对应的模型会有两个一模一样的情况哪?这就要说说这个项目管理方面的情况了,刚开始时我们这个项目有两组人共同开发,并且思路都是不一样的比如:有一组开发人员从来不用mybatis自动成的Dao接口文件和对应的数据库与模型的映射文件,他们认为里面的好多代码都没有用非常的多余,而另外的一组人员则是习惯使用这些自动生成的文件!而且命名的习惯也不相同,为此还专门的开过一次小会制订了一个项目命名规范的文件!不过有些习惯上的地方仍然没有完全的统一,就造成类似这样的问题的发生!再者就是项目组的成员不是很稳定,最多时开发人员有二十几个,中途有离职的有调到其他项目的!这样代码的质量很难有非常好的保证,项目管理非常重要,这一块我还没有具体的涉及,只是看过几本书,不过从实际的经验来看还是能实际的体会到一些东西在的,比如:
1:项目组的人员最好不是拼凑而成的,多少有些默契合作起来才能更加的顺畅
2:有些东西最好统一,最好在动手开始做项目的时候就跟大家讲清楚,尽量选择一种更优的方式,比如:编码的风格、命名规范、项目的基本业务知识等等
3:就公司而言,我想在项目的开发期间保持项目组的人员尽量少的变动可能会节约更多的开发成本,除非加入一些非常牛的新成员
当然,对于查错也有一条比较灵验的经验值得分享:当感觉有问题愣是查不出来的时候,不妨从头再来,对于你认为不可能出错的地方也去仔仔细细的查查,说不定会有所获!