美文网首页Java基础技巧工具
惨痛教训——记一次生产变更失败记录

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

作者: 莫问以 | 来源:发表于2019-05-24 15:07 被阅读0次

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

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

    代码修改注释一定记得备份.png

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

    private void parseFmt5201List(Element ele, List<EcfnPayList> ecfnPayList) throws ParseException {
            @SuppressWarnings("unchecked")
            List<Element> eles = ele.elements("Detail");
            for (Element e : eles) {
                EcfnPayList epl = new EcfnPayList();
                epl.setStatus("0");
                @SuppressWarnings("unchecked")
                List<Element> 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");
            }
        }
    
    执行结果.png

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

    相关文章

      网友评论

        本文标题:惨痛教训——记一次生产变更失败记录

        本文链接:https://www.haomeiwen.com/subject/bfpwzqtx.html