背景
最近在做Mongo上的表数据的迁移,原本应该是DBA要干的活,但是想着DBA排期比较长,加上我们开发的权限又非常有限,而且数据量又没有多少,就想着自己开发个小小的程序从旧实例上查,写到新实例上去算了。于是就遇到了今天要分享的这个坑。
有问题代码
这个方法目的是查询表的所有数据,但是返回的结果实际会有问题,返回来的并非全量数据。原因是分好页之后,在去查询每页的数据的时候都重新再查询了下集合,然后再取分页数据,这个过程中有其他的线程也去修改这个集合的数据,集合数据变化了就会导致查询到的分页数据不正确。
/**
* 这个方法目的是查询表的所有数据,但是返回的结果实际会有问题,会出现数据不完整
* 原因是分好页之后,查询每页的数据的时候都重新查询了集合,这个过程中有其他的线程也去修改这个集合的数据,
* 集合数据变化了就会导致查询到的分页数据不正确。
* @param dbName
* @param tableName
* @return
*/
public List<Document> queryCollections_Error(String dbName, String tableName) {
List<Document> result = new ArrayList<>();
long count = this.count(dbName, tableName);
int pageSize = 1000;
for (int idx = 0; idx < count; idx += pageSize) {
result.addAll(this.queryCollectionsByPage(dbName, tableName, idx, pageSize));
}
return result;
}
改正后的代码
改正后的代码,是只能保证了在程序开始运行的这一刻mongo表的快照的数据同步到新表是准确的,但是同步程序运行过程中如果表数据发生了变更,这部分数据是没有变更到新实例上面去的,这个大家需要注意。我们的业务是对内的业务,而且数据量不大,因此在同步的时候禁写掉这个服务中断时间可以接受。如果是不可接受服务中断,那么应该要考虑下全量+增量的方案。
public List<Document> queryCollections(String dbName, String tableName) {
List<Document> result = new ArrayList<>();
MongoCollection<Document> mongoCollection = this.mongoClient.getDatabase(dbName).getCollection(tableName);
long count = mongoCollection.countDocuments();
int pageSize = 1000;
for (int idx = 0; idx < count; idx += pageSize) {
FindIterable<Document> iterable = mongoCollection.find().skip(idx).limit(pageSize);
iterable.forEach(new Block<Document>() {
@Override
public void apply(Document document) {
result.add(JSON.parseObject(JSON.toJSONString(document), Document.class));
}
});
}
return result;
}