关于Date使用不当的bug

发布时间 2023-04-02 21:12:48作者: 永恒&

关于Date使用不当的bug

1、背景

用户调用接口,传入一个参数分钟,表示想要查询距离现在多少分钟的记录。

有的时候会查不到记录。

2、排查过程

大致代码。

  • 获取当前的时间的date对象now,通过now的时间戳计算前beforeMinute的时间戳,转换成date对象
  • 查询 executeTime >= before && executeTime <= now && status == 1 的记录
	@GetMapping("/test")
    public void testMongo(Integer beforeMinute) {
        // 计算执行时间前后时间
        Date now = new Date(); // 获取当前时间的Date对象
        Date before = new Date(now.getTime() - beforeMinute * 60 * 1000); // 获取前beforeMinute的Date对象

        andCriteriaList.add(Criteria.where("executeTime").gte(before));
        andCriteriaList.add(Criteria.where("executeTime").lte(now));
        andCriteriaList.add(Criteria.where("status").is(Integer.parseInt("1"))); // 状态为 1
        Criteria combinedCriteria = new Criteria();
        combinedCriteria.andOperator(andCriteriaList.toArray(new Criteria[0]));
        Query query = new Query();
        query.addCriteria(combinedCriteria);
        List<AuditLogDownloadBean> list = mongoTemplate.find(query, AuditLogDownloadBean.class);
        for (AuditLogDownloadBean bean : list) {
            System.out.println(bean.getId() + " "+ bean.getExecuteTime() + " " + bean.getJobName());
        }
        return ;
    }

经过debug,问题出在构造before的date对象上,有时会出现before计算出来的时间戳会比now还要大,所以导致查不到数据。

Date before = new Date(now.getTime() - beforeMinute * 60 * 1000);
/**
	当查询三天前的记时,传入的参数=3x24x60=43200
	此时,beforeMinute * 60 * 1000 = 2,592,000,000 共十位,而int的最大值也是十位 2,147,483,647,所以产生了整型溢出,
	整个表达式的值相当于 now.getTime() - (-1702967296), 所以会比now还要大,最终导致查不到数据。
*/

// 改正 
Date before = new Date(now.getTime() - beforeMinute * 60L * 1000);

3、总结

  1. Java 中数字字面量默认是整型的
  2. 当一个表达式中含有变量时,要注意其是否可能产生整型溢出
  3. 当一个表达式中包含Long类型时,整个表达式的值会向Long转变