环境
mongodb库:2.4、2.6
驱动包:
mongodb-driver-2.11.3.jar
mongodb-driver-3.4.2.jar
bson-3.4.2.jar
mongodb-driver-core-3.4.2.jar
情形
使用mongodb
驱动包为2.11
的写法:
DBCollection collection = db.getCollection("gg_module_access_statistics");
BasicDBObject fields = new BasicDBObject();
fields.append("address", 1);
BasicDBObject query = new BasicDBObject();
query.append("status", 1);
DBCursor cursor = collection.find(query, fields).limit(10);
while(cursor.hasNext()){
DBObject o = cursor.next();
System.out.println(o.get("address"));
}
cursor.close();
使用驱动包mongodb-driver-3.4.2
中写法为:
FindIterable<Document> findIterable = collection.find().limit(10);
//这一步开始查询数据库
MongoCursor<Document> iterator = findIterable.iterator();
while(iterator.hasNext()){
Document o = iterator.next();
System.out.println(o.get("address"));
}
iterator.close();
可以看出mongodb-driver-2.11
版本的写法是:
1、遍历的是游标,DBCursor
DBCursor cursor = collection.find(new BasicDBObject(), fields).limit(10);
2、游标的元素是DBObject类型的
DBObject o = cursor.next();
3、当从mongodb数据库中读取数组时,默认是BasicDBLIst类型的。
而在mongodb-driver-3.4
版本中:
1、遍历的是迭代器FindIterable。
FindIterable<Document> findIterable = collection.find().limit(10);
MongoCursor<Document> iterator = findIterable.iterator();
2、游标的元素是Document类型
Document o = iterator.next();
3、当从mongodb数据中读取数组时,默认是ArrayList类型。
思路
刚开始我看到上区别后,我得出结果,我们公司永远都不可能升级成mongodb3+
。
能得出这样的结论,真的说明我对java
封装思想理解不够。公司的后端架构师把3.4
中的Document
和Iterable
等都封装起来。比如以前2.4
中写法是BasicDBObject
和DBCursor
,那么就把它们(Document
等)封装进去。这样就可以做到从2.4版本
升级到3.4
的版本啦。
就贴一张公司封装图片:
总之假设不想更改现有的代码,又想升级到mongodb3.4
那就是把3.4
中新写法都封装起来,封装的类名就是以前2.4
中的类名。只不过封装好了之后需要重新引入包(也就是对着项目名 按:ctrl + shift + o)。
BasicDBList
这个数组在驱动包2.4
中默认数组,也就是mongodb
库中的数组都会被转成这个类型。
但是在驱动包3.4
中,已不是它啦,而是java
的ArrayList
类型。
在驱动包mongodb2.4
中
在驱动包mongodb3.4
中
之所以这一块单独讲是因为,公司昨天在替换包时,发现有这么一段代码(强制类型转换):
while(cursor.hasNext()){
DBObject o = cursor.next();
System.out.println((BasicDBList)o.get("G3_01_01_02_access_account"));
//同事为了BasicDBList中Iterable方法而做了这样一个强转,结果在本次驱动包升级时
//出现了bug,虽然你可以说是驱动包兼容不好,但是这种强转本身就不对。
}
因为驱动包3.4
现在使用的是ArrayList
而不是BasicDBList
,所以就报错啦!
这里也告诉我们,以后再做类型转换时,能转成java
本身类型就转java
本身类型。不要因为框架类型的某些特性而选择框架自己的类型。mongodb驱动包2.4与3.4
就是一个活生生的例子。框架本身就是基本java
语法,理论上,框架能做到的,java
本身语法一定能做到。
源码
昨天非常想知道源码是怎么实现的。(一直找到凌晨12点半,明天还得上班)
所以去官网把相应的源码都下载下来了,再在eclipse
中关联下。
源码包名:
bson-3.4.2-sources.jar
mongodb-driver-core-3.4.2-sources.jar
mongo-java-driver-3.4.2-sources.jar
驱动包官网:https://oss.sonatype.org/content/repositories/releases/org/mongodb/
经过我一路断点,终于找到了具体实现的代码。
具体是在bson-3.4.2
这个包中:
其中的readValue()
方法:
这里我把具体代码贴出来:
private Object readValue(final BsonReader reader, final DecoderContext decoderContext) {
BsonType bsonType = reader.getCurrentBsonType();
if (bsonType == BsonType.NULL) {
reader.readNull();
return null;
} else if (bsonType == BsonType.ARRAY) {//数组就走这里
return readList(reader, decoderContext);
} else if (bsonType == BsonType.BINARY && BsonBinarySubType.isUuid(reader.peekBinarySubType()) && reader.peekBinarySize() == 16) {//从3.4开始支持对UUID处理
return registry.get(UUID.class).decode(reader, decoderContext);
}
return valueTransformer.transform(bsonTypeCodecMap.get(bsonType).decode(reader, decoderContext));
}
//如果是数组,就会调用这个方法
private List<Object> readList(final BsonReader reader, final DecoderContext decoderContext) {
reader.readStartArray();
List<Object> list = new ArrayList<Object>();//就在这里了
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
list.add(readValue(reader, decoderContext));
}
reader.readEndArray();
return list;
}
我们再看到这样一段代码:
return valueTransformer.transform(bsonTypeCodecMap.get(bsonType).decode(reader, decoderContext));
重点是decode(reader, decoderContext)
中decode()
方法。
如果是Long
类型:
public class LongCodec implements Codec<Long> {
@Override
public void encode(final BsonWriter writer, final Long value, final EncoderContext encoderContext) {
writer.writeInt64(value);
}
@Override
public Long decode(final BsonReader reader, final DecoderContext decoderContext) {
return reader.readInt64();//就会调用这个方法
}
@Override
public Class<Long> getEncoderClass() {
return Long.class;
}
}
而readInt64()
方法:
@Override
public long readInt64() {
checkPreconditions("readInt64", BsonType.INT64);
setState(getNextState());
return doReadInt64();
}
doReadInt64
源码:
@Override
protected long doReadInt64() {
return bsonInput.readInt64();
}
readInt64
源码:
@Override
public long readInt64() {
ensureOpen();
ensureAvailable(8);
return buffer.getLong();
}
getLong()
源码:
@Override
public long getLong() {
return buf.getLong();
}
getLong()
源码:
public long getLong() {
return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian);
}
static long getLong(ByteBuffer bb, int bi, boolean bigEndian) {
return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi);
}
static long getLongB(ByteBuffer bb, int bi) {
return makeLong(bb._get(bi ),
bb._get(bi + 1),
bb._get(bi + 2),
bb._get(bi + 3),
bb._get(bi + 4),
bb._get(bi + 5),
bb._get(bi + 6),
bb._get(bi + 7));
}
// -- get/put long --
static private long makeLong(byte b7, byte b6, byte b5, byte b4,
byte b3, byte b2, byte b1, byte b0)
{
return ((((long)b7 ) << 56) |
(((long)b6 & 0xff) << 48) |
(((long)b5 & 0xff) << 40) |
(((long)b4 & 0xff) << 32) |
(((long)b3 & 0xff) << 24) |
(((long)b2 & 0xff) << 16) |
(((long)b1 & 0xff) << 8) |
(((long)b0 & 0xff) ));
}
这里的buf
是ByteBuffer
类型,ByteBuffer
是java.nio.ByteBuffer
。到这这里我们知道了,mongodb3.4
驱动包底层是使用java nio
技术。nio
是非阻塞输入输出流。