您的位置:首页 > 数据库 > Mongodb

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

2017-01-22 12:59 661 查看
最近项目用到了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的地方,把时区设置成了格林时间,如下图:

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

至此,时间的问题就分析完了,分享给大家,希望大家以后遇到不要绕弯路~第一次写博客,有点紧张~有什么不对欢迎指正~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mongodb java 日期