java用spring-data-mongodb操作mongodb的时间问题

来源:互联网 发布:网络卖彩票会坐牢吗 编辑:程序博客网 时间:2024/05/16 11:06

最近项目用到了mongodb,做了个时间段查询,自己调试的时候,发现把时间放到查询条件类QueryBuilder中之后就会自动向前推8小时。。纠结了好几天,终于找到答案,这里跟大家分享一下,希望大家会避免。

先贴出主要代码:

// 构建查询条件QueryBuilder queryBuilder = new QueryBuilder();Date startDate = DateUtil.fromStringToDate("yyyy-MM-dd HH:mm:ss", "2017-01-07 10:00:00");queryBuilder.put("createTime").greaterThanEquals(startDate);// 要查询的字段BasicDBObject fieldsObject = new BasicDBObject();fieldsObject.put("name", 1);fieldsObject.put("age", 1);fieldsObject.put("createTime", 1);// 执行查询Query query = new BasicQuery(queryBuilder.get(), fieldsObject);List<Map> list = mongoTemplate.find(query, Map.class, COLLECTION);

当queryBuilder.put(“createTime”).greaterThanEquals(startDate);执行之后,debug调试查看queryBuilder会发现startDate的值向前推了8小时,百度了半天发现是时区的问题,可是也没有具体解答,只好看源码跟进问题。

一开始以为是QueryBuilder的greaterThanEquals等方法做了时区的转换,于是找出来greaterThanEquals方法的源码:

    public QueryBuilder greaterThanEquals(Object object) {        addOperand(QueryOperators.GTE, object);        return this;    }    //里面做了一个addOperand方法,我们看addOperand的源码    private void addOperand(String op, Object value) {        if(op == null) {            if (_hasNot) {                value = new BasicDBObject(QueryOperators.NOT, value);                _hasNot = false;            }            // 这里预警,put之后_query里的时间就变了            _query.put(_currentKey, value);            return;        }        Object storedValue = _query.get(_currentKey);        BasicDBObject operand;        if(!(storedValue instanceof DBObject)) {            operand = new BasicDBObject();            if (_hasNot) {                DBObject notOperand = new BasicDBObject(QueryOperators.NOT, operand);                _query.put(_currentKey, notOperand);                _hasNot = false;            } else {                _query.put(_currentKey, operand);            }        } else {            operand = (BasicDBObject)_query.get(_currentKey);            if (operand.get(QueryOperators.NOT) != null) {                operand = (BasicDBObject) operand.get(QueryOperators.NOT);            }        }        operand.put(op, value);    }

源码跟进来之后,发现是 _query.put(_currentKey, value);这句之后时间就会变,大家看图,我们先看传进去的时间,2017年01月10日10点整,如下图:
这里写图片描述

再来看put之后的_query值,下图:
这里写图片描述
可以看到,变成了2017年1月7日2点,于是又把问题放到了_query上面,看他的put里干了什么,我们要知道_query是什么类型。继续看源码:

public QueryBuilder() {        _query = new BasicDBObject();    }

初始化的时候创建了BasicDBObject对象,继续到BasicDBObject中看put方法,如下:

public class BasicBSONObject extends LinkedHashMap<String,Object> implements BSONObject {    ...    public Object put( String key , Object val ){        return super.put( key , val );    }    ...}

到这也不用看了,发现put方法是直接用的父类,点进去是HashMap类的put方法。。。到这线索没了,已疯。。。左思右想,spring-data-mongo肯定不会这么坑,一定是我的打开方式不对,于是想先往BasicDBObject中put个时间值,再把他get出来,看看get出来的值还改变吗,结果get出来的值没有向前推8小时,没有没有没有。

为了进一步证实调用数据库查询时用的是我们传进去的时间,还是向前推8小时之后的时间,我在mongodb中插入一条时间为2017-01-10 10:00:00的数据,然后在java中传2017-01-10 10:00:00这个时间条件进行查询,可以看到put之后仍然变成了2017-01-10 02:00:00,可是查询结果确实是查到了时间为2017-01-10 10:00:00的数据。

可以看到,这与我们的期望值一致,可是中间出了些问题,纠结了一段时间,突然想到会不会是toString的时候把时区改了呢,导致打印和显示的时候出来的是格林时间,事实证明真的是这样,BasicDBObject在toString方法中有个处理java.util.Date的地方,把时区设置成了格林时间,如下图:

现在我该说什么。。我们眼睛看到的,未必是真实的。。。

至此,时间的问题就分析完了,分享给大家,希望大家以后遇到不要绕弯路~第一次写博客,有点紧张~有什么不对欢迎指正~~

2 0