关于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、总结
- Java 中数字字面量默认是整型的
- 当一个表达式中含有变量时,要注意其是否可能产生整型溢出
- 当一个表达式中包含Long类型时,整个表达式的值会向Long转变