惨痛教训——记一次生产变更失败记录

这两天都在忙着补录数据,基本已补录OK,甚好没对系统造成太大影响。简单梳理一下事件经过,望对各位初入Java无甚经验的程序猿能起到一个很好的警示作用。

由于该系统要做一次大变更,各种报文规范进行了一次新更改,所以就由我带着刚入职的新同事一起完成该项工作,三月份的时候,基本代码已编写完毕,剩下的调试工作,就交给了新同事(主要配合人行、财政、机构部的人一起),检测代码异常或者漏洞。

惨痛教训——记一次生产变更失败记录_第1张图片
代码修改注释一定记得备份.png

这个也没什么难度,所以我就投入到了其他的工作当中,只等财政通知上线。经过机构部进行测试(反复测试N多遍),同意上线变更。上周五晚上,进行了代码变更,周一的时候,有数据接入进来,正常的做业务,待下午的时候,系统退款异常,检测数据,发现数据库有一个字段为空值。

private void parseFmt5201List(Element ele, List ecfnPayList) throws ParseException {
        @SuppressWarnings("unchecked")
        List eles = ele.elements("Detail");
        for (Element e : eles) {
            EcfnPayList epl = new EcfnPayList();
            epl.setStatus("0");
            @SuppressWarnings("unchecked")
            List list = e.elements();
            for (Element ee : list) {
                /* 支付明细Id */
                if ("Id".equals(ee.getName())) {
                    epl.setPayListId(ee.getStringValue());
                }
                /* 财政直接支付凭证Id */
                else if ("VoucherBillId".equals(ee.getName())) {
                    epl.setVoucherBillId(ee.getStringValue());
                }
                /* 财政直接支付凭证单号 */
                else if ("VoucherBillNo".equals(ee.getName())) {
                    epl.setVoucherBillNo(ee.getStringValue());
                }
                /* 支付申请序号 (原本需要删除的字段 取报文明细单VoucherDetailNo的值)  0421 ykx*/
                else if ("VoucherDetailNo".equals(ee.getName())) {
                    // epl.setVoucherNo(ee.getStringValue());
                }
                /* 资金性质编码 */
                else if ("FundTypeCode".equals(ee.getName())) {
                    epl.setFundTypeCode(ee.getStringValue());
                }
                ………………………………………………
                /* 备注 */
                else if ("Remark".equals(ee.getName())) {
                    epl.setRemark(ee.getStringValue());
                }
                /* 实际支付日期 */
                else if ("XPayDate".equals(ee.getName())) {
                    if (ee.getStringValue() != null && ee.getStringValue().trim().length() == 8) {
                        epl.setxPayDate(ee.getStringValue());
                    }
                }
                
                /* 预留字段1 */
                else if ("Hold1".equals(ee.getName())) {
                    epl.setHold1(ee.getStringValue());
                }
                /* 预留字段2 */
                else if ("Hold2".equals(ee.getName())) {
                    epl.setHold2(ee.getStringValue());
                }
                /* 预留字段3 */
                else if ("Hold3".equals(ee.getName())) {
                    epl.setHold3(ee.getStringValue());
                }
                /* 预留字段4 */
                else if ("Hold4".equals(ee.getName())) {
                    epl.setHold4(ee.getStringValue());
                }
                              /* 新增报文 */
                else if ("VoucherDetailNo".equals(ee.getName())) {
                    epl.setVoucherDetailNo(ee.getStringValue());
                } else if ("GovExpEcoCode".equals(ee.getName())) {
                    epl.setGovExpEcoCode(ee.getStringValue());
                } else if ("GovExpEcoName".equals(ee.getName())) {
                    epl.setGovExpEcoName(ee.getStringValue());
                } else if ("DepExpEcoCode".equals(ee.getName())) {
                    epl.setDepExpEcoCode(ee.getStringValue());
                } else if ("DepExpEcoName".equals(ee.getName())) {
                    epl.setDepExpEcoName(ee.getStringValue());
                } else if ("TrackingID".equals(ee.getName())) {
                    epl.setTrackingID(ee.getStringValue());
                }
            }
            ecfnPayList.add(epl);
        }
    }

我发现数据库VoucherDetailNo这个字段值为空,而同时新增加的字段GovExpEcoCode、GovExpEcoName等等都有值,一下子就有些不淡定了,怎么可能单单略过VoucherDetailNo字段不解析呢?
先暂停读取报文自动任务,截了一段xml报文至测试环境进行本地测验,发现没什么问题,可以读取VoucherDetailNo的值,可是生产为什么没有读取该值呢?变更还是自己亲自进行的,按理说不会有错,于是截取生产class文件,进行反编译,结果就得到了上面的代码。

  /* 支付申请序号 (原本需要删除的字段 取报文明细单VoucherDetailNo的值)  0421 ykx*/
                else if ("VoucherDetailNo".equals(ee.getName())) {
                    // epl.setVoucherNo(ee.getStringValue());
                }
  /* 支付申请序号 */
// else if ("VoucherNo".equals(ee.getName())) {
                   // epl.setVoucherNo(ee.getStringValue());
                //}

这一段真是坑死我,这一段是被我注释了的(第2个代码块),不知道为什么就被同事取消改为了代码块1。后来问了一下他原因,他说:财政人员说原VoucherNo的值跟新VoucherDetailNo的值时一样的,所以他就保留了。保留也就保留了,为什么这个地方要加注释呢?
// epl.setVoucherNo(ee.getStringValue());
[这个地方加了注释导致的结果就是==无法Update明细单VoucherDetailNo的值为VoucherNo]

注释就注释了,可是我比对SVN代码与我本地代码的时候,发现一模一样,结果拿该同事本地代码与SVN代码比对,发现他的这一个地方与SVN有异同。我向他递了一个大大的问号,他说:测试过程中忘了同步了!

上线变更的class文件是该同事提供的,我检查了变更文件,不多不少,所以就上线生产了(这个地方我也有责任,该同事算个新手,没什么项目经验,但功底还是挺不错的)我就问他,你这么改VoucherDetailNo有值吗?他说有值,我看了看测试环境数据库,该字段还真有值。然后我问他,你这段代码什么时候改的?上测试环境了吗?他说记不清了。。。。估计他后面不注意改了改,自己又忘记了,所以把编译好的class文件发给了我,就导致该次变更异常。

这种情况其实也正常,在测试过程中,基本也是他负责代码的调试(主要是数据验证、报文规范检查),所以我就发了这样一段代码给他:

public static void main(String[] args) {
        Example("2");
    }

    public static void Example(String msg) {
        if (msg.equals("1")) {
             System.out.println("1");
        } else if (msg.equals("2")) {
//          System.out.println("2");
        } else if (msg.equals("888")) {
            System.out.println("888");
        } else if (msg.equals("111")) {
            System.out.println("111");
        } else if (msg.equals("2")) {
            System.out.println("Hello World");
        }else {
            System.out.println("nothing");
        }
        System.err.println("end----");
    }

我问他:你说会输出Hello World吗?他犹豫了一下还是点了点头,结果他自己跑该代码的时候,也发现自己问题所在了。

如果多个else if并列,只要第一个if条件成立,后面的else ifelse都不会执行,即使满足else if的条件也不会执行。

如果多个if,那么最后的else会执行;else与最近的if匹配,包括else ififif满足条件执行,最后的else满不满足条件,都执行。

public static void main(String[] args) {
        MoreIf("2");
    }
public static void MoreIf(String msg){
        if (msg.equals("1")) {
            System.out.println("1");
        }
        if (msg.equals("2")) {
            System.out.println("2");
        }
        if (msg.equals("111")) {
            System.out.println("111");
        }
        if (msg.equals("888")) {
            System.out.println("888");
        } else if (msg.equals("666")) {
            System.out.println("666");
        } else {
            System.err.println("Hello World");
        }
    }
惨痛教训——记一次生产变更失败记录_第2张图片
执行结果.png

由于VoucherNo为空,VoucherDetailNo也为空,是没办法直接修改数据了,只好把当天的日志拿下来,写了一段程序,读取日志中的xml报文,输出sql的Update语句进行变更,可看下一篇!

你可能感兴趣的:(惨痛教训——记一次生产变更失败记录)