线上问题排查-int类型的溢出问题

368 阅读2分钟

一 场景

系统:xx系统\
功能界面:【xxx】\
功能按钮:直接打印\
单号:xxx
问题描述:用户反馈2021/09/07 15:15打印时,系统弹框提示“修改报文已发送,
发送时间未超过10分钟,请10分钟后操作”,实际修改报文是2021-08-13 14:24发送的,完全超过了10分钟,为什么还提示

二 分析

定位代码

```
    /**
     * 修改报文只检验发送时间
     *
     * @param eirSendList
     * @return
     */
    private String checkEirEmAlterSend(List<InboundEirSend> eirSendList) {
        StringBuilder result = new StringBuilder();
        StringBuilder checkTime = new StringBuilder("以下箱号修改报文已发送,发送时间未超过10分钟,请10分钟后操作:");
        boolean isCheckTime = false;
        for (InboundEirSend entity : eirSendList) {
            int sendStatus = entity.getSendStatus();
            if (sendStatus == 0) {
                continue;
            }
            Date sendTime = entity.getSendTime();
            boolean isMore = eirSendUtilService.isMoreTimeToNow(sendTime, 10);
            if (isMore) {
                isCheckTime = true;
                checkTime.append(entity.getCtnNo()).append(COMMA);
            }
        }
        if (isCheckTime) {
            result.append(eirSendUtilService.subStringValue(checkTime)).append(SEMICOLON);
        }
        return result.toString();
    }
```

时间判断代码

    /**
     * 比较时间和当前时间差值 是否在moreminute 内
     *
     * @param targetDate
     * @param moreMinute
     * @return
     */
    public boolean isMoreTimeToNow(Date targetDate, int moreMinute) {
        boolean result = false;
        if (targetDate == null) {
            return result;
        }
        long diffMilliseconds = System.currentTimeMillis() - targetDate.getTime();
        int diffMin = (int) diffMilliseconds / 60000;
        if (diffMin < moreMinute) {
            result = true;
        }
        return result;
    }

看上去并没有问题,找了产品确认几次,的确存在这样的问题,于是自己写了一个测试代码,复原了当时生产时的时间,发现的确存在问题

  int diffMin = (int) diffMilliseconds / 60000;
  

执行后,居然出现了负数,导致

    if (diffMin < moreMinute) {
        result = true;
    }

result 为true,导致了问题的产生,那么为什么会产生负数呢?

原来是int类型溢出问题,我们看下int类型的区间

-2147483648——2147483647; 如果超出这个区间就会出现溢出问题,因为一个数据类型的最大值和最小值是一个循环,也就是说在最大值的基础上再扩大数值或者在最小值的基础上再缩小数值,会跳到相反的最值上面。 这就解释了为什么会出现负数。 最后修改为不通过int类型而通过long类型解决了这个问题

public boolean isMoreTimeToNow(Date targetDate, long moreMinute) {
    boolean result = false;
    if (targetDate == null) {
        return result;
    }
    long diffMilliseconds = System.currentTimeMillis() - targetDate.getTime();
    long diffMin = diffMilliseconds / 60000;
    if (diffMin < moreMinute) {
        result = true;
    }
    return result;
}

long类型的区间为 -9223372036854775808——9223372036854775807 满足业务需求

三 结语

这次问题的排查,得到的启示就是,对于可能存再的问题代码,自己一定要亲自去测,自己亲自去写,这样才能更好地排查出问题。